Compare commits

...

32 Commits

Author SHA1 Message Date
Denis Flaven
06e389f14c Fixed a potential XSS vulnerability.
SVN:2.0.1[3667]
2015-07-30 09:27:23 +00:00
Denis Flaven
e90f4e1232 #966 Prevent duplication of attachments when the form gets reloaded.
SVN:2.0.1[3294]
2014-07-30 08:24:35 +00:00
Denis Flaven
474df98dfa #966 (continue'd): Allow attachments of several files to the same ticket (the previous fix breaks after attaching 1 file)
SVN:2.0.1[3289]
2014-07-25 15:21:07 +00:00
Denis Flaven
ce88d10766 #966 Fix for a bug caused by Google Chrome version 36: the selected attachment was added several times (up to 10 or more!).
SVN:2.0.1[3283]
2014-07-21 15:43:57 +00:00
Denis Flaven
225eab9bd3 #966 Fix for a bug caused by Google Chrome version 36: the selected attachment was added several times (up to 10 or more!).
SVN:2.0.1[3282]
2014-07-21 15:43:34 +00:00
Denis Flaven
42b0a8c3cb Bug fix : missing semicolons were causing an error with IE9.
SVN:2.0.1[3109]
2014-03-26 15:01:44 +00:00
Denis Flaven
484fa42113 #870: when a user deletes all her/his shortcuts at once, this was deleting all the shortcuts for all users.
SVN:2.0.1[3101]
2014-03-12 14:09:15 +00:00
Denis Flaven
5c1149ac68 Protect the initialization with a try ... catch, in order to protect that rest of the page in case of trouble.
SVN:2.0.1[3076]
2014-02-05 17:11:55 +00:00
Romain Quetiez
1dbb94a2e1 Fix for the validation of mandatory fields in the portal (reintegrated from trunk)
SVN:2.0.1[3053]
2014-01-07 14:10:39 +00:00
Romain Quetiez
df1869dfe3 PHP Mail transport to allow 100% of recipients in BCC (proposed on github) -reintegrated from trunk
SVN:2.0.1[3046]
2013-12-13 10:30:21 +00:00
Denis Flaven
22ee1cd6f4 #856: allow asynchronous emails to have an empty 'to' recipient... (not used anyway)
SVN:2.0.1[3045]
2013-12-12 18:06:16 +00:00
Denis Flaven
0b14bf605c #795 Issue when using the actual (id) value of an external key as a reconciliation field
SVN:2.0.1[2917]
2013-10-16 08:49:53 +00:00
Denis Flaven
02717360d0 Show all types of Actions from the "Notifications/Actions" tab.
SVN:2.0.1[2912]
2013-10-15 12:01:20 +00:00
Denis Flaven
230710eb04 #791 Protect against single quotes in localized strings...
SVN:2.0.1[2910]
2013-10-14 17:11:30 +00:00
Denis Flaven
6581c02301 #793 provide the default '=' and '!=' operators for all types of Computed Fields.
SVN:2.0.1[2904]
2013-10-14 14:20:24 +00:00
Romain Quetiez
f925a21735 retrofit Change in the Notifications panel: show/create all types of Action (not only ActionEmail)
SVN:2.0.1[2897]
2013-10-11 14:22:17 +00:00
Denis Flaven
8796e5fa74 Retrofit the useful DoPostRequest function which was used (and defined) in several extensions.
SVN:2.0.1[2887]
2013-10-11 08:41:22 +00:00
Denis Flaven
249dd03b18 New pattern accepting the new global Top Level Domains (gTLD)
SVN:2.0.1[2868]
2013-09-27 07:31:21 +00:00
Denis Flaven
94ba2c3c1c Protect the deletion of objects with very long friendly names
SVN:2.0.1[2862]
2013-09-24 16:23:26 +00:00
Denis Flaven
7ec9022bd7 Allow for comparisons of the module's versions in the expression of dependencies. For example one can now say "itop-config-mgmt/>=2.0.2" for a dependency.
SVN:2.0.1[2854]
2013-09-23 13:22:02 +00:00
Romain Quetiez
7ba2cf59de Shortest fix ever!!!! Sort icons based on the class name (ksort => asort)
SVN:2.0.1[2851]
2013-09-13 10:53:19 +00:00
Romain Quetiez
fdacbf6d0f #763 Could not use "configure this list" once a stop watch has been added to the list, which is a pitty because such attributes are not aimed at being displayed in lists!
SVN:2.0.1[2849]
2013-09-11 09:59:23 +00:00
Romain Quetiez
580de372e0 #752 Notifications sent several times (or too late) when MySQL is hosted on another server
SVN:2.0.1[2830]
2013-08-23 07:36:20 +00:00
Denis Flaven
0faa33a0e5 Allow "Support Agents" to put an Incident in "Pending" state.
SVN:2.0.1[2815]
2013-08-01 08:28:41 +00:00
Denis Flaven
1aff819f8f #747 protect against the non-existence of UserRequest (since the module is not always installed)
SVN:2.0.1[2812]
2013-07-30 16:28:26 +00:00
Denis Flaven
0ac9fce207 #746 allow adding an AttributeBlob with is_null_allowed = true to an existing Data Model. (same issue fixed also for AttributeOneWayPassword).
SVN:2.0.1[2809]
2013-07-25 09:24:18 +00:00
Denis Flaven
8a8de2bcc3 Export the content of the CaseLogs in "spreadsheet" format, with some tricks to preserve the formatting in Excel.
SVN:2.0.1[2805]
2013-07-17 17:12:52 +00:00
Denis Flaven
3b4ff79ea3 Make the portal (slightly) more configurable
SVN:2.0.1[2798]
2013-07-12 14:02:13 +00:00
Romain Quetiez
0fcbc040fd Cosmetics on the user portal -reintegrated from trunk
SVN:2.0.1[2777]
2013-06-14 15:40:58 +00:00
Romain Quetiez
ae6e0c5242 #736 Could not delete objects unless you are authorized to bulk delete -reintegrated from trunk
SVN:2.0.1[2770]
2013-06-07 07:32:38 +00:00
Denis Flaven
1ce8046c46 #734 Fixed a regression on reconciliation keys during CSV import.
SVN:2.0.1[2762]
2013-05-29 08:57:35 +00:00
Romain Quetiez
56eba6de4c Created branch 2.0.1
SVN:2.0.1[2759]
2013-05-22 12:33:48 +00:00
31 changed files with 1346 additions and 1138 deletions

View File

@@ -240,6 +240,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$sTip .= Dict::S('Core:Synchro:LastSynchro').'<br/>'.$aStruct['last_synchro']."</p>"; $sTip .= Dict::S('Core:Synchro:LastSynchro').'<br/>'.$aStruct['last_synchro']."</p>";
} }
$sSynchroIcon = '&nbsp;<img style="vertical-align:middle;" id="synchro_icon" src="../images/locked.png"/>'; $sSynchroIcon = '&nbsp;<img style="vertical-align:middle;" id="synchro_icon" src="../images/locked.png"/>';
$sTip = addslashes($sTip);
$oPage->add_ready_script("$('#synchro_icon').qtip( { content: '$sTip', show: 'mouseover', hide: { fixed: true }, style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"); $oPage->add_ready_script("$('#synchro_icon').qtip( { content: '$sTip', show: 'mouseover', hide: { fixed: true }, style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
} }
@@ -431,15 +432,28 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
} }
if (count($aTriggers) > 0) if (count($aTriggers) > 0)
{ {
// Display notifications regarding the object
$iId = $this->GetKey(); $iId = $this->GetKey();
$sTriggersList = implode(',', $aTriggers); $sTriggersList = implode(',', $aTriggers);
$oNotifSearch = DBObjectSearch::FromOQL("SELECT EventNotificationEmail AS Ev JOIN Trigger AS T ON Ev.trigger_id = T.id WHERE T.id IN ($sTriggersList) AND Ev.object_id = $iId"); $aNotifSearches = array();
$oNotifSet = new DBObjectSet($oNotifSearch); $iNotifsCount = 0;
$sCount = ($oNotifSet->Count() > 0) ? ' ('.$oNotifSet->Count().')' : ''; $aNotificationClasses = MetaModel::EnumChildClasses('EventNotification', ENUM_CHILD_CLASSES_EXCLUDETOP);
foreach($aNotificationClasses as $sNotifClass)
{
$aNotifSearches[$sNotifClass] = DBObjectSearch::FromOQL("SELECT $sNotifClass AS Ev JOIN Trigger AS T ON Ev.trigger_id = T.id WHERE T.id IN ($sTriggersList) AND Ev.object_id = $iId");
$oNotifSet = new DBObjectSet($aNotifSearches[$sNotifClass]);
$iNotifsCount += $oNotifSet->Count();
}
// Display notifications regarding the object: on block per subclass to have the intersting columns
$sCount = ($iNotifsCount > 0) ? ' ('.$iNotifsCount.')' : '';
$oPage->SetCurrentTab(Dict::S('UI:NotificationsTab').$sCount); $oPage->SetCurrentTab(Dict::S('UI:NotificationsTab').$sCount);
$oBlock = new DisplayBlock($oNotifSearch, 'list', false);
$oBlock->Display($oPage, 'notifications', array('menu' => false)); foreach($aNotificationClasses as $sNotifClass)
{
$oPage->p(MetaModel::GetClassIcon($sNotifClass, true).'&nbsp;'.MetaModel::GetName($sNotifClass));
$oBlock = new DisplayBlock($aNotifSearches[$sNotifClass], 'list', false);
$oBlock->Display($oPage, 'notifications_'.$sNotifClass, array('menu' => false));
}
} }
} }
} }
@@ -1219,6 +1233,13 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$aRow[] = '<td>'.date('H:i:s', $iDate).'</td>'; $aRow[] = '<td>'.date('H:i:s', $iDate).'</td>';
} }
} }
else if($oAttDef instanceof AttributeCaseLog)
{
$rawValue = $oObj->Get($sAttCodeEx);
$outputValue = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
// Trick for Excel: treat the content as text even if it begins with an equal sign
$aRow[] = '<td x:str>'.$outputValue.'</td>';
}
else else
{ {
$rawValue = $oObj->Get($sAttCodeEx); $rawValue = $oObj->Get($sAttCodeEx);

View File

@@ -231,7 +231,7 @@ abstract class Dashboard
public function Render($oPage, $bEditMode = false, $aExtraParams = array()) 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 = new $this->sLayoutClass;
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams); $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode) if (!$bEditMode)

View File

@@ -1059,7 +1059,7 @@ class DashletBadge extends Dashlet
$oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']); $oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']);
ksort($aClasses); asort($aClasses);
$aValues = array(); $aValues = array();
foreach($aClasses as $sClass => $sClass) foreach($aClasses as $sClass => $sClass)
{ {

View File

@@ -64,6 +64,7 @@ class PortalWebPage extends NiceWebPage
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts $sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sAppContext = addslashes($oAppContext->GetForLink()); $sAppContext = addslashes($oAppContext->GetForLink());
$this->add_dict_entry('UI:FillAllMandatoryFields');
if ($sAlternateStyleSheet != '') if ($sAlternateStyleSheet != '')
{ {
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css"); $this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");

View File

@@ -15,6 +15,6 @@
</itoptab> </itoptab>
<itoptab name="UI:NotificationsMenu:Actions"> <itoptab name="UI:NotificationsMenu:Actions">
<h2><itopstring>UI:NotificationsMenu:AvailableActions</itopstring></h2> <h2><itopstring>UI:NotificationsMenu:AvailableActions</itopstring></h2>
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">SELECT ActionEmail</itopblock> <itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">SELECT Action</itopblock>
</itoptab> </itoptab>
</itoptabs> </itoptabs>

View File

@@ -869,6 +869,60 @@ class utils
static public function GetSafeId($sId) static public function GetSafeId($sId)
{ {
return str_replace(array(':', '[', ']', '+', '-'), '_', $sId); return str_replace(array(':', '[', ']', '+', '-'), '_', $sId);
} }
/**
* Helper to execute an HTTP POST request
* Source: http://netevil.org/blog/2006/nov/http-post-from-php-without-curl
* originaly named after do_post_request
* Does not require cUrl but requires openssl for performing https POSTs.
*
* @param string $sUrl The URL to POST the data to
* @param hash $aData The data to POST as an array('param_name' => value)
* @param string $sOptionnalHeaders Additional HTTP headers as a string with newlines between headers
* @return string The result of the POST request
* @throws Exception
*/
static public function DoPostRequest($sUrl, $aData, $sOptionnalHeaders = null)
{
// $sOptionnalHeaders is a string containing additional HTTP headers that you would like to send in your request.
$sData = http_build_query($aData);
$aParams = array('http' => array(
'method' => 'POST',
'content' => $sData,
'header'=> "Content-type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($sData)."\r\n",
));
if ($sOptionnalHeaders !== null)
{
$aParams['http']['header'] .= $sOptionnalHeaders;
}
$ctx = stream_context_create($aParams);
$fp = @fopen($sUrl, 'rb', false, $ctx);
if (!$fp)
{
global $php_errormsg;
if (isset($php_errormsg))
{
throw new Exception("Wrong URL: $sUrl, $php_errormsg");
}
elseif ((strtolower(substr($sUrl, 0, 5)) == 'https') && !extension_loaded('openssl'))
{
throw new Exception("Cannot connect to $sUrl: missing module 'openssl'");
}
else
{
throw new Exception("Wrong URL: $sUrl");
}
}
$response = @stream_get_contents($fp);
if ($response === false)
{
throw new Exception("Problem reading data from $sUrl, $php_errormsg");
}
return $response;
}
} }
?> ?>

View File

@@ -140,7 +140,7 @@ class AsyncSendEmail extends AsyncTask
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));

View File

@@ -2078,7 +2078,7 @@ class AttributeEmailAddress extends AttributeString
public function GetValidationPattern() public function GetValidationPattern()
{ {
// return "^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$"; // return "^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$";
return "^[a-zA-Z0-9._&-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"; return "^[a-zA-Z0-9._&-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,}$";
} }
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true) public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
@@ -3360,26 +3360,26 @@ class AttributeBlob extends AttributeDefinition
public function FromSQLToValue($aCols, $sPrefix = '') public function FromSQLToValue($aCols, $sPrefix = '')
{ {
if (!isset($aCols[$sPrefix])) if (!array_key_exists($sPrefix, $aCols))
{ {
$sAvailable = implode(', ', array_keys($aCols)); $sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
} }
$sMimeType = $aCols[$sPrefix]; $sMimeType = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : '';
if (!isset($aCols[$sPrefix.'_data'])) if (!array_key_exists($sPrefix.'_data', $aCols))
{ {
$sAvailable = implode(', ', array_keys($aCols)); $sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '".$sPrefix."_data' from {$sAvailable}"); throw new MissingColumnException("Missing column '".$sPrefix."_data' from {$sAvailable}");
} }
$data = $aCols[$sPrefix.'_data']; $data = isset($aCols[$sPrefix.'_data']) ? $aCols[$sPrefix.'_data'] : null;
if (!isset($aCols[$sPrefix.'_filename'])) if (!array_key_exists($sPrefix.'_filename', $aCols))
{ {
$sAvailable = implode(', ', array_keys($aCols)); $sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '".$sPrefix."_filename' from {$sAvailable}"); throw new MissingColumnException("Missing column '".$sPrefix."_filename' from {$sAvailable}");
} }
$sFileName = $aCols[$sPrefix.'_filename']; $sFileName = isset($aCols[$sPrefix.'_filename']) ? $aCols[$sPrefix.'_filename'] : '';
$value = new ormDocument($data, $sMimeType, $sFileName); $value = new ormDocument($data, $sMimeType, $sFileName);
return $value; return $value;
@@ -4127,19 +4127,19 @@ class AttributeOneWayPassword extends AttributeDefinition
public function FromSQLToValue($aCols, $sPrefix = '') public function FromSQLToValue($aCols, $sPrefix = '')
{ {
if (!isset($aCols[$sPrefix])) if (!array_key_exists($sPrefix, $aCols))
{ {
$sAvailable = implode(', ', array_keys($aCols)); $sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}"); throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
} }
$hashed = $aCols[$sPrefix]; $hashed = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : '';
if (!isset($aCols[$sPrefix.'_salt'])) if (!array_key_exists($sPrefix.'_salt', $aCols))
{ {
$sAvailable = implode(', ', array_keys($aCols)); $sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '".$sPrefix."_salt' from {$sAvailable}"); throw new MissingColumnException("Missing column '".$sPrefix."_salt' from {$sAvailable}");
} }
$sSalt = $aCols[$sPrefix.'_salt']; $sSalt = isset($aCols[$sPrefix.'_salt']) ? $aCols[$sPrefix.'_salt'] : '';
$value = new ormPassword($hashed, $sSalt); $value = new ormPassword($hashed, $sSalt);
return $value; return $value;
@@ -4506,7 +4506,7 @@ class AttributeComputedFieldVoid extends AttributeDefinition
public function GetBasicFilterOperators() public function GetBasicFilterOperators()
{ {
return array(); return array("="=>"equals", "!="=>"differs from");
} }
public function GetBasicFilterLooseOperator() public function GetBasicFilterLooseOperator()
{ {

View File

@@ -296,10 +296,17 @@ class BulkChange
$oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass()); $oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass());
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol) foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
{ {
// The foreign attribute is one of our reconciliation key if ($sForeignAttCode == 'id')
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode); {
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues); $value = (int) $aRowData[$iCol];
$oReconFilter->AddCondition($sForeignAttCode, $value); }
else
{
// The foreign attribute is one of our reconciliation key
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
}
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
} }

View File

@@ -176,7 +176,7 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this))); $oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
$oMyChangeOp->Set("objkey", $objkey); $oMyChangeOp->Set("objkey", $objkey);
$oMyChangeOp->Set("fclass", get_class($this)); $oMyChangeOp->Set("fclass", get_class($this));
$oMyChangeOp->Set("fname", $this->GetRawName()); $oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2013 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -162,8 +162,7 @@ class ormStopWatch
} }
else else
{ {
$iElapsedTemp = ''; //$this->ComputeDuration($oHostObject, $oAttDef, $this->iLastStart, time()); $aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
$aProperties['Elapsed'] = $this->iTimeSpent.' + '.$iElapsedTemp.' s + <img src="../images/indicator.gif">';
} }
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted); $aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
@@ -183,7 +182,7 @@ class ormStopWatch
} }
$aProperties[$iPercent.'%'] = $sThresholdDesc; $aProperties[$iPercent.'%'] = $sThresholdDesc;
} }
$sRes = "<TABLE class=\"listResults\">"; $sRes = "<TABLE>";
$sRes .= "<TBODY>"; $sRes .= "<TBODY>";
foreach ($aProperties as $sProperty => $sValue) foreach ($aProperties as $sProperty => $sValue)
{ {
@@ -387,9 +386,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
public function Process($iTimeLimit) public function Process($iTimeLimit)
{ {
$aList = array();
foreach (MetaModel::GetClasses() as $sClass) foreach (MetaModel::GetClasses() as $sClass)
{ {
$aList = array();
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{ {
if ($oAttDef instanceof AttributeStopWatch) if ($oAttDef instanceof AttributeStopWatch)
@@ -398,8 +397,8 @@ class CheckStopWatchThresholds implements iBackgroundProcess
{ {
$iPercent = $aThresholdData['percent']; // could be different than the index ! $iPercent = $aThresholdData['percent']; // could be different than the index !
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()"; $sNow = date('Y-m-d H:i:s');
//echo $sExpression."<br/>\n"; $sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '$sNow'";
$oFilter = DBObjectSearch::FromOQL($sExpression); $oFilter = DBObjectSearch::FromOQL($sExpression);
$oSet = new DBObjectSet($oFilter); $oSet = new DBObjectSet($oFilter);
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch())) while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
@@ -407,7 +406,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
$sClass = get_class($oObj); $sClass = get_class($oObj);
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold; $aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
// Execute planned actions // Execute planned actions
// //
@@ -416,7 +414,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
$sVerb = $aActionData['verb']; $sVerb = $aActionData['verb'];
$aParams = $aActionData['params']; $aParams = $aActionData['params'];
$sParams = implode(', ', $aParams); $sParams = implode(', ', $aParams);
//echo "Calling: $sVerb($sParams)<br/>\n";
$aCallSpec = array($oObj, $sVerb); $aCallSpec = array($oObj, $sVerb);
call_user_func_array($aCallSpec, $aParams); call_user_func_array($aCallSpec, $aParams);
} }
@@ -438,12 +435,12 @@ class CheckStopWatchThresholds implements iBackgroundProcess
// Activate any existing trigger // Activate any existing trigger
// //
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)); $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oSet = new DBObjectSet( $oTriggerSet = new DBObjectSet(
DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"), DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
array(), // order by array(), // order by
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold) array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
); );
while ($oTrigger = $oSet->Fetch()) while ($oTrigger = $oTriggerSet->Fetch())
{ {
$oTrigger->DoActivate($oObj->ToArgs('this')); $oTrigger->DoActivate($oObj->ToArgs('this'));
} }
@@ -454,9 +451,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
} }
$iProcessed = count($aList); $iProcessed = count($aList);
return "Triggered $iProcessed threshold(s)"; return "Triggered $iProcessed threshold(s):".implode(", ", $aList);
} }
} }
?>

View File

@@ -350,7 +350,8 @@ EOF
$oPage->add('</span>'); $oPage->add('</span>');
$oPage->add('<div style="clear:both"></div>'); $oPage->add('<div style="clear:both"></div>');
$sMaxUpload = $this->GetMaxUpload(); $sMaxUpload = $this->GetMaxUpload();
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> '.$sMaxUpload); $oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> '.$sMaxUpload);
$oPage->add_ready_script('$("#file").off("change.itop-attachments").on("change.itop-attachments", function() {ajaxFileUpload();});'); // Workaround for a Chrome 36 bug causing multiple (12!) times the same upload. See http://www.redmine.org/issues/17151
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>'); $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->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
$oPage->add('</fieldset>'); $oPage->add('</fieldset>');

View File

@@ -33,4 +33,11 @@ define('PORTAL_REQUEST_FORM_ATTRIBUTES', 'title,description,impact,urgency,workg
define('PORTAL_ATTCODE_TYPE', ''); // optional if the type has to be set define('PORTAL_ATTCODE_TYPE', ''); // optional if the type has to be set
define('PORTAL_SET_TYPE_FROM', ''); // The attribute to get the type from (Subcategory) define('PORTAL_SET_TYPE_FROM', ''); // The attribute to get the type from (Subcategory)
define('PORTAL_TICKETS_LIST_ZLIST', 'finalclass,title,start_date,status,servicesubcategory_id,priority,caller_id');
define('PORTAL_TICKETS_SEARCH_CRITERIA','ref,start_date,close_date,service_id,caller_id');
define('PORTAL_TICKETS_CLOSED_ZLIST', 'title,start_date,close_date,servicesubcategory_id');
// json encoded lists for the portal...
define('PORTAL_TICKET_DETAILS_ZLIST', '{"col:left":["ref","caller_id","servicesubcategory_id","title","description","solution"],"col:right":["status","priority","start_date","resolution_date","last_update","agent_id"]}');
?> ?>

View File

@@ -350,7 +350,8 @@ EOF
$oPage->add('</span>'); $oPage->add('</span>');
$oPage->add('<div style="clear:both"></div>'); $oPage->add('<div style="clear:both"></div>');
$sMaxUpload = $this->GetMaxUpload(); $sMaxUpload = $this->GetMaxUpload();
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> '.$sMaxUpload); $oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file"><span style="display:none;" id="attachment_loading">&nbsp;<img src="../images/indicator.gif"></span> '.$sMaxUpload);
$oPage->add_ready_script('$("#file").off("change.itop-attachments").on("change.itop-attachments", function() {ajaxFileUpload();});'); // Workaround for a Chrome 36 bug causing multiple (12!) times the same upload. See http://www.redmine.org/issues/17151
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>'); $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->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
$oPage->add('</fieldset>'); $oPage->add('</fieldset>');

View File

@@ -1452,28 +1452,31 @@
$sUserString = CMDBChange::GetCurrentUserName(); $sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString."(automatic resolution)"); $oMyChange->Set("userinfo", $sUserString."(automatic resolution)");
$iChangeId = $oMyChange->DBInsert(); $iChangeId = $oMyChange->DBInsert();
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket"; if (MetaModel::IsValidClass('UserRequest'))
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), {
array(), $sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
array( $oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
'ticket' => $this->GetKey(), array(),
) array(
); 'ticket' => $this->GetKey(),
//automatically resolve child requests )
while($oRequest = $oChildRequestSet->Fetch()) );
{ //automatically resolve child requests
if ( $oRequest->Get('status') != 'resolved') while($oRequest = $oChildRequestSet->Fetch())
{ {
$oRequest->set('servicesubcategory_id',$this->Get('servicesubcategory_id')); if ( $oRequest->Get('status') != 'resolved')
$oRequest->set('service_id',$this->Get('service_id')); {
$oRequest->set('team_id',$this->Get('team_id')); $oRequest->set('servicesubcategory_id',$this->Get('servicesubcategory_id'));
$oRequest->set('agent_id',$this->Get('agent_id')); $oRequest->set('service_id',$this->Get('service_id'));
$oRequest->set('resolution_code',$this->Get('resolution_code')); $oRequest->set('team_id',$this->Get('team_id'));
$oRequest->set('solution','Automatically resolved by incident:[[Incident:'.$this->Get('ref').']]'); $oRequest->set('agent_id',$this->Get('agent_id'));
$oRequest->ApplyStimulus('ev_autoresolve'); $oRequest->set('resolution_code',$this->Get('resolution_code'));
$oRequest->DBUpdateTracked($oMyChange); $oRequest->set('solution','Automatically resolved by incident:[[Incident:'.$this->Get('ref').']]');
} $oRequest->ApplyStimulus('ev_autoresolve');
} $oRequest->DBUpdateTracked($oMyChange);
}
}
}
//automatically resolve child incidents //automatically resolve child incidents
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket"; $sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";
@@ -1507,6 +1510,8 @@
<type>LifecycleAction</type> <type>LifecycleAction</type>
<code><![CDATA[ public function UpdateChildRequestLog() <code><![CDATA[ public function UpdateChildRequestLog()
{ {
if (!MetaModel::IsValidClass('UserRequest')) return true; // Do nothing
$sLogPublic = utils::ReadPostedParam('attr_public_log', null,false,'raw_data'); $sLogPublic = utils::ReadPostedParam('attr_public_log', null,false,'raw_data');
if ( $sLogPublic != null) if ( $sLogPublic != null)
{ {

View File

@@ -315,6 +315,7 @@
<action id="ev_reassign" xsi:type="stimulus">allow</action> <action id="ev_reassign" xsi:type="stimulus">allow</action>
<action id="ev_resolve" xsi:type="stimulus">allow</action> <action id="ev_resolve" xsi:type="stimulus">allow</action>
<action id="ev_close" xsi:type="stimulus">allow</action> <action id="ev_close" xsi:type="stimulus">allow</action>
<action id="ev_pending" xsi:type="stimulus">allow</action>
</actions> </actions>
</group> </group>
<group id="class:UserRequest"> <group id="class:UserRequest">

View File

@@ -33,4 +33,9 @@ define('PORTAL_REQUEST_FORM_ATTRIBUTES', 'title,description,impact,urgency');
define('PORTAL_ATTCODE_TYPE', ''); // optional if the type has to be set define('PORTAL_ATTCODE_TYPE', ''); // optional if the type has to be set
define('PORTAL_SET_TYPE_FROM', ''); // The attribute to get the type from (Subcategory) define('PORTAL_SET_TYPE_FROM', ''); // The attribute to get the type from (Subcategory)
define('PORTAL_TICKETS_LIST_ZLIST', 'finalclass,title,start_date,status,servicesubcategory_id,priority,caller_id');
define('PORTAL_TICKETS_SEARCH_CRITERIA','ref,start_date,close_date,service_id,caller_id');
define('PORTAL_TICKETS_CLOSED_ZLIST', 'title,start_date,close_date,servicesubcategory_id');
// json encoded lists for the portal...
define('PORTAL_TICKET_DETAILS_ZLIST', '{"col:left":["ref","caller_id","servicesubcategory_id","title","description","solution"],"col:right":["status","priority","start_date","resolution_date","last_update","agent_id"]}');
?> ?>

View File

@@ -33,4 +33,9 @@ define('PORTAL_REQUEST_FORM_ATTRIBUTES', 'title,description,impact,urgency');
define('PORTAL_ATTCODE_TYPE', 'request_type'); // optional if the type has to be set define('PORTAL_ATTCODE_TYPE', 'request_type'); // optional if the type has to be set
define('PORTAL_SET_TYPE_FROM', 'request_type'); // The attribute to get the type from (Subcategory) define('PORTAL_SET_TYPE_FROM', 'request_type'); // The attribute to get the type from (Subcategory)
define('PORTAL_TICKETS_LIST_ZLIST', 'finalclass,title,start_date,status,servicesubcategory_id,priority,caller_id');
define('PORTAL_TICKETS_SEARCH_CRITERIA','ref,start_date,close_date,service_id,caller_id');
define('PORTAL_TICKETS_CLOSED_ZLIST', 'title,start_date,close_date,servicesubcategory_id');
// json encoded lists for the portal...
define('PORTAL_TICKET_DETAILS_ZLIST', '{"col:left":["ref","caller_id","servicesubcategory_id","title","description","solution"],"col:right":["status","priority","start_date","resolution_date","last_update","agent_id"]}');
?> ?>

View File

@@ -782,6 +782,7 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
'Portal:Refresh' => 'Neu laden', 'Portal:Refresh' => 'Neu laden',
'Portal:Back' => 'Zurück', 'Portal:Back' => 'Zurück',
'Portal:WelcomeUserOrg' => 'Wilkommen %1$s, von %2$s', 'Portal:WelcomeUserOrg' => 'Wilkommen %1$s, von %2$s',
'Portal:TitleDetailsFor_Request' => 'Deails für Benutzeranfrage',
'Portal:ShowOngoing' => 'Zeige offene Requests', 'Portal:ShowOngoing' => 'Zeige offene Requests',
'Portal:ShowClosed' => 'Zeige geschlossene Requests', 'Portal:ShowClosed' => 'Zeige geschlossene Requests',
'Portal:CreateNewRequest' => 'Einen neuen Request erstellen', 'Portal:CreateNewRequest' => 'Einen neuen Request erstellen',

View File

@@ -754,7 +754,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Applying %1$s on object: %2$s in state %3$s to target state: %4$s.', 'UI:Apply_Stimulus_On_Object_In_State_ToTarget_State' => 'Applying %1$s on object: %2$s in state %3$s to target state: %4$s.',
'UI:ObjectCouldNotBeWritten' => 'The object could not be written: %1$s', 'UI:ObjectCouldNotBeWritten' => 'The object could not be written: %1$s',
'UI:PageTitle:FatalError' => 'iTop - Fatal Error', 'UI:PageTitle:FatalError' => 'iTop - Fatal Error',
'UI:SystemIntrusion' => 'Access denied. You have trying to perform an operation that is not allowed for you.', 'UI:SystemIntrusion' => 'Access denied. You have requested an operation that is not allowed for you.',
'UI:FatalErrorMessage' => 'Fatal error, iTop cannot continue.', 'UI:FatalErrorMessage' => 'Fatal error, iTop cannot continue.',
'UI:Error_Details' => 'Error: %1$s.', 'UI:Error_Details' => 'Error: %1$s.',
@@ -943,6 +943,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'Portal:Refresh' => 'Refresh', 'Portal:Refresh' => 'Refresh',
'Portal:Back' => 'Back', 'Portal:Back' => 'Back',
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s', 'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
'Portal:TitleDetailsFor_Request' => 'Details for request',
'Portal:ShowOngoing' => 'Show open requests', 'Portal:ShowOngoing' => 'Show open requests',
'Portal:ShowClosed' => 'Show closed requests', 'Portal:ShowClosed' => 'Show closed requests',
'Portal:CreateNewRequest' => 'Create a new request', 'Portal:CreateNewRequest' => 'Create a new request',

View File

@@ -943,6 +943,7 @@ Cuando se asocien con un disparador, cada acción recibe un número de "orden",
'Portal:Refresh' => 'Actualizar', 'Portal:Refresh' => 'Actualizar',
'Portal:Back' => 'Atrás', 'Portal:Back' => 'Atrás',
'Portal:WelcomeUserOrg' => 'Bienvenido %1$s, de %2$s', 'Portal:WelcomeUserOrg' => 'Bienvenido %1$s, de %2$s',
'Portal:TitleDetailsFor_Request' => 'Detalles de la Solicitud',
'Portal:ShowOngoing' => 'Mostrar Requerimientos Abiertos', 'Portal:ShowOngoing' => 'Mostrar Requerimientos Abiertos',
'Portal:ShowClosed' => 'Mostrar Requerimientos Cerrados', 'Portal:ShowClosed' => 'Mostrar Requerimientos Cerrados',
'Portal:CreateNewRequest' => 'Crear Requerimiento', 'Portal:CreateNewRequest' => 'Crear Requerimiento',

View File

@@ -786,6 +786,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'Portal:Refresh' => 'Rafraîchir', 'Portal:Refresh' => 'Rafraîchir',
'Portal:Back' => 'Retour', 'Portal:Back' => 'Retour',
'Portal:WelcomeUserOrg' => 'Bienvenue %1$s (%2$s)', 'Portal:WelcomeUserOrg' => 'Bienvenue %1$s (%2$s)',
'Portal:TitleDetailsFor_Request' => 'Détail de la requête',
'Portal:ShowOngoing' => 'Requêtes en cours', 'Portal:ShowOngoing' => 'Requêtes en cours',
'Portal:ShowClosed' => 'Requêtes fermées', 'Portal:ShowClosed' => 'Requêtes fermées',
'Portal:CreateNewRequest' => 'Créer une nouvelle requête', 'Portal:CreateNewRequest' => 'Créer une nouvelle requête',

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ jQuery.extend(
var fileId = 'jUploadFile' + id; var fileId = 'jUploadFile' + id;
var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>'); var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
var oldElement = jQuery('#' + fileElementId); var oldElement = jQuery('#' + fileElementId);
var newElement = jQuery(oldElement).clone(); var newElement = jQuery(oldElement).clone(true);
jQuery(oldElement).attr('id', fileId); jQuery(oldElement).attr('id', fileId);
jQuery(oldElement).before(newElement); jQuery(oldElement).before(newElement);
jQuery(oldElement).appendTo(form); jQuery(oldElement).appendTo(form);
@@ -131,12 +131,12 @@ jQuery.extend(
jQuery.handleError(s, xml, null, e); jQuery.handleError(s, xml, null, e);
} }
}, 100) }, 100);
xml = null xml = null;
} }
} };
// Timeout checker // Timeout checker
if ( s.timeout > 0 ) if ( s.timeout > 0 )
{ {
@@ -197,7 +197,9 @@ jQuery.extend({
s.error( xhr, status, e ); s.error( xhr, status, e );
// If we have some XML response text (e.g. from an AJAX call) then log it in the console // If we have some XML response text (e.g. from an AJAX call) then log it in the console
else if(xhr.responseText) else if(xhr.responseText)
console.log(xhr.responseText); {
//console.log(xhr.responseText);
}
} }
}); });

View File

@@ -438,59 +438,70 @@ function sprintf(format, etc) {
this.construct = function(settings) { this.construct = function(settings) {
return this.each(function() { return this.each(function() {
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
var table = this, pager = config.container; try
{
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
var table = this, pager = config.container;
this.ajax_request = null; this.ajax_request = null;
config.selectedSize = parseInt($(".pagesize",pager).val()); config.selectedSize = parseInt($(".pagesize",pager).val());
setPageSize(table,config.selectedSize, false);
restoreParams(table, config);
//$(this).trigger("appendCache"); // Load the data
//console.log($.tablesorterPager);
applySelection(table);
$('.gotopage',pager).click(function() { setPageSize(table,config.selectedSize, false);
var idx = $(this).attr('page'); restoreParams(table, config);
table.config.page = idx;
moveToPage(table);
});
$(config.cssFirst,pager).click(function() {
moveToFirstPage(table);
return false;
});
$(config.cssNext,pager).click(function() {
moveToNextPage(table);
return false;
});
$(config.cssPrev,pager).click(function() {
moveToPrevPage(table);
return false;
});
$(config.cssLast,pager).click(function() {
moveToLastPage(table);
return false;
});
$(config.cssPageSize,pager).change(function() {
setPageSize(table,parseInt($(this).val()), true);
return false;
});
$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
return checkAll(table, pager, this.checked);
});
$(table).bind('load_selection', function() { //$(this).trigger("appendCache"); // Load the data
loadSelection(table, pager); //console.log($.tablesorterPager);
applySelection(table); applySelection(table);
});
$(table).bind('check_all', function() { $('.gotopage',pager).click(function() {
checkAll(table, pager, true); var idx = $(this).attr('page');
}); table.config.page = idx;
moveToPage(table);
});
$(config.cssFirst,pager).click(function() {
moveToFirstPage(table);
return false;
});
$(config.cssNext,pager).click(function() {
moveToNextPage(table);
return false;
});
$(config.cssPrev,pager).click(function() {
moveToPrevPage(table);
return false;
});
$(config.cssLast,pager).click(function() {
moveToLastPage(table);
return false;
});
$(config.cssPageSize,pager).change(function() {
setPageSize(table,parseInt($(this).val()), true);
return false;
});
$(table).find(':checkbox.checkAll').removeAttr('onclick').click(function() {
return checkAll(table, pager, this.checked);
});
$(table).bind('load_selection', function() {
loadSelection(table, pager);
applySelection(table);
});
$(table).bind('check_all', function() {
checkAll(table, pager, true);
});
}
catch(err)
{
if (console && console.log)
{
console.log(err);
}
}
}); });
}; };
} }

View File

@@ -126,13 +126,7 @@ class Swift_Transport_MailTransport implements Swift_Transport
$toHeader = $message->getHeaders()->get('To'); $toHeader = $message->getHeaders()->get('To');
$subjectHeader = $message->getHeaders()->get('Subject'); $subjectHeader = $message->getHeaders()->get('Subject');
if (!$toHeader) $to = $toHeader ? $toHeader->getFieldBody() : '';
{
throw new Swift_TransportException(
'Cannot send message without a recipient'
);
}
$to = $toHeader->getFieldBody();
$subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; $subject = $subjectHeader ? $subjectHeader->getFieldBody() : '';
$reversePath = $this->_getReversePath($message); $reversePath = $this->_getReversePath($message);
@@ -143,7 +137,10 @@ class Swift_Transport_MailTransport implements Swift_Transport
$messageStr = $message->toString(); $messageStr = $message->toString();
$message->getHeaders()->set($toHeader); if ($toHeader)
{
$message->getHeaders()->set($toHeader);
}
$message->getHeaders()->set($subjectHeader); $message->getHeaders()->set($subjectHeader);
//Separate headers from body //Separate headers from body

View File

@@ -938,9 +938,9 @@ try
$id = utils::ReadParam('id', ''); $id = utils::ReadParam('id', '');
$oObj = MetaModel::GetObject($sClass, $id); $oObj = MetaModel::GetObject($sClass, $id);
$aObjects[] = $oObj; $aObjects[] = $oObj;
if (!UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, DBObjectSet::FromObject($oObj))) if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromObject($oObj)))
{ {
throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClass)); throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClassLabel));
} }
} }
else else
@@ -957,11 +957,21 @@ try
{ {
$aObjects[] = MetaModel::GetObject($sClass, $iId); $aObjects[] = MetaModel::GetObject($sClass, $iId);
} }
if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects))) if (count($aObjects) == 1)
{ {
throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClass)); if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
{
throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
}
}
else
{
if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
{
throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
}
$oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
} }
$oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
} }
// Go for the common part... (delete single, delete bulk, delete confirmed) // Go for the common part... (delete single, delete bulk, delete confirmed)
cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed'); cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');

View File

@@ -936,6 +936,7 @@ EOF
case 'shortcut_delete_go': case 'shortcut_delete_go':
$oSearch = new DBObjectSearch('Shortcut'); $oSearch = new DBObjectSearch('Shortcut');
$oSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$aShortcuts = utils::ReadMultipleSelection($oSearch); $aShortcuts = utils::ReadMultipleSelection($oSearch);
foreach ($aShortcuts as $iShortcut) foreach ($aShortcuts as $iShortcut)
{ {

View File

@@ -84,33 +84,43 @@ function SelectServiceCategory($oP, $oUserOrg)
{ {
$aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS); $aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS);
$oP->add("<div class=\"wizContainer\" id=\"form_select_service\">\n");
$oP->WizardFormStart('request_wizard', 1);
$oP->add("<h1 id=\"select_category\">".Dict::S('Portal:SelectService')."</h1>\n");
$oP->add("<table>\n");
$oSearch = DBObjectSearch::FromOQL(PORTAL_SERVICECATEGORY_QUERY); $oSearch = DBObjectSearch::FromOQL(PORTAL_SERVICECATEGORY_QUERY);
$oSearch->AllowAllData(); // In case the user has the rights on his org only $oSearch->AllowAllData(); // In case the user has the rights on his org only
$oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey()));
while($oService = $oSet->Fetch()) if ($oSet->Count() == 1)
{ {
$id = $oService->GetKey(); $oService = $oSet->Fetch();
$sChecked = ""; $iSvcCategory = $oService->GetKey();
if (isset($aParameters['service_id']) && ($id == $aParameters['service_id'])) // Only one Category, skip this step in the wizard
{ SelectServiceSubCategory($oP, $oUserOrg, $iSvcCategory);
$sChecked = "checked";
}
$oP->p("<tr><td style=\"vertical-align:top\"><p><input name=\"attr_service_id\" $sChecked type=\"radio\" id=\"service_$id\" value=\"$id\"></p></td><td style=\"vertical-align:top\"><p><b><label for=\"service_$id\">".$oService->GetName()."</label></b></p>");
$oP->p("<p>".$oService->GetAsHTML('description')."</p></td></tr>");
} }
$oP->add("</table>\n"); else
{
$oP->add("<div class=\"wizContainer\" id=\"form_select_service\">\n");
$oP->WizardFormStart('request_wizard', 1);
$oP->DumpHiddenParams($aParameters, array('service_id')); $oP->add("<h1 id=\"select_category\">".Dict::S('Portal:SelectService')."</h1>\n");
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_request\">"); $oP->add("<table>\n");
$oP->WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL); while($oService = $oSet->Fetch())
$oP->WizardFormEnd(); {
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectOneService')); $id = $oService->GetKey();
$oP->add("</div>\n"); $sChecked = "";
if (isset($aParameters['service_id']) && ($id == $aParameters['service_id']))
{
$sChecked = "checked";
}
$oP->p("<tr><td style=\"vertical-align:top\"><p><input name=\"attr_service_id\" $sChecked type=\"radio\" id=\"service_$id\" value=\"$id\"></p></td><td style=\"vertical-align:top\"><p><b><label for=\"service_$id\">".$oService->GetName()."</label></b></p>");
$oP->p("<p>".$oService->GetAsHTML('description')."</p></td></tr>");
}
$oP->add("</table>\n");
$oP->DumpHiddenParams($aParameters, array('service_id'));
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_request\">");
$oP->WizardFormButtons(BUTTON_NEXT | BUTTON_CANCEL); // NO back button since it's the first step of the Wizard
$oP->WizardFormEnd();
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectOneService'));
$oP->add("</div>\n");
}
} }
/** /**
@@ -118,14 +128,23 @@ function SelectServiceCategory($oP, $oUserOrg)
* and based on the page's parameter 'service_id' * and based on the page's parameter 'service_id'
* @param WebPage $oP Web page for the form output * @param WebPage $oP Web page for the form output
* @param Organization $oUserOrg The organization of the current user * @param Organization $oUserOrg The organization of the current user
* @param $iSvcId Id of the selected service in case of pass-through (when there is only one service)
* @return void * @return void
*/ */
function SelectServiceSubCategory($oP, $oUserOrg) function SelectServiceSubCategory($oP, $oUserOrg, $iSvcId = null)
{ {
$aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS); $aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS);
$iWizardButtons = 0;
$iSvcId = $aParameters['service_id']; if ($iSvcId == null)
{
$iSvcId = $aParameters['service_id'];
}
else
{
$aParameters['service_id'] = $iSvcId;
$iWizardButtons = BUTTON_NEXT;
}
$iDefaultSubSvcId = isset($aParameters['servicesubcategory_id']) ? $aParameters['servicesubcategory_id'] : 0; $iDefaultSubSvcId = isset($aParameters['servicesubcategory_id']) ? $aParameters['servicesubcategory_id'] : 0;
$iDefaultWizNext = 2; $iDefaultWizNext = 2;
@@ -133,45 +152,56 @@ function SelectServiceSubCategory($oP, $oUserOrg)
$oSearch = DBObjectSearch::FromOQL(PORTAL_SERVICE_SUBCATEGORY_QUERY); $oSearch = DBObjectSearch::FromOQL(PORTAL_SERVICE_SUBCATEGORY_QUERY);
$oSearch->AllowAllData(); // In case the user has the rights on his org only $oSearch->AllowAllData(); // In case the user has the rights on his org only
$oSet = new CMDBObjectSet($oSearch, array(), array('svc_id' => $iSvcId, 'org_id' => $oUserOrg->GetKey())); $oSet = new CMDBObjectSet($oSearch, array(), array('svc_id' => $iSvcId, 'org_id' => $oUserOrg->GetKey()));
$oServiceCategory = MetaModel::GetObject('Service', $iSvcId, false, true /* allow all data*/); if ($oSet->Count() == 1)
if (is_object($oServiceCategory))
{ {
$oP->add("<div class=\"wizContainer\" id=\"form_select_servicesubcategory\">\n"); // Only one sub service, skip this step of the wizard
$oP->add("<h1 id=\"select_subcategory\">".Dict::Format('Portal:SelectSubcategoryFrom_Service', $oServiceCategory->GetName())."</h1>\n"); $oSubService = $oSet->Fetch();
$oP->WizardFormStart('request_wizard', $iDefaultWizNext); $iSubSvdId = $oSubService->GetKey();
$oP->add("<table>\n"); RequestCreationForm($oP, $oUserOrg, $iSvcId, $iSubSvdId);
while($oSubService = $oSet->Fetch())
{
$id = $oSubService->GetKey();
$sChecked = "";
if ($id == $iDefaultSubSvcId)
{
$sChecked = "checked";
}
$oP->add("<tr>");
$oP->add("<td style=\"vertical-align:top\">");
$oP->add("<p><input name=\"attr_servicesubcategory_id\" $sChecked type=\"radio\" id=\"servicesubcategory_$id\" value=\"$id\"></p>");
$oP->add("</td>");
$oP->add("<td style=\"vertical-align:top\">");
$oP->add("<p><b><label for=\"servicesubcategory_$id\">".$oSubService->GetName()."</label></b></p>");
$oP->add("<p>".$oSubService->GetAsHTML('description')."</p>");
$oP->add("</td>");
$oP->add("</tr>");
}
$oP->add("</table>\n");
$oP->DumpHiddenParams($aParameters, array('servicesubcategory_id'));
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_request\">");
$oP->WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL);
$oP->WizardFormEnd();
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectAServiceSubCategory'));
$oP->add("</div>\n");
} }
else else
{ {
$oP->p("Error: Invalid Service: id = $iSvcId"); $oServiceCategory = MetaModel::GetObject('Service', $iSvcId, false, true /* allow all data*/);
if (is_object($oServiceCategory))
{
$oP->add("<div class=\"wizContainer\" id=\"form_select_servicesubcategory\">\n");
$oP->add("<h1 id=\"select_subcategory\">".Dict::Format('Portal:SelectSubcategoryFrom_Service', $oServiceCategory->GetName())."</h1>\n");
$oP->WizardFormStart('request_wizard', $iDefaultWizNext);
$oP->add("<table>\n");
while($oSubService = $oSet->Fetch())
{
$id = $oSubService->GetKey();
$sChecked = "";
if ($id == $iDefaultSubSvcId)
{
$sChecked = "checked";
}
$oP->add("<tr>");
$oP->add("<td style=\"vertical-align:top\">");
$oP->add("<p><input name=\"attr_servicesubcategory_id\" $sChecked type=\"radio\" id=\"servicesubcategory_$id\" value=\"$id\"></p>");
$oP->add("</td>");
$oP->add("<td style=\"vertical-align:top\">");
$oP->add("<p><b><label for=\"servicesubcategory_$id\">".$oSubService->GetName()."</label></b></p>");
$oP->add("<p>".$oSubService->GetAsHTML('description')."</p>");
$oP->add("</td>");
$oP->add("</tr>");
}
$oP->add("</table>\n");
$oP->DumpHiddenParams($aParameters, array('servicesubcategory_id'));
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"create_request\">");
$iWizardButtons |= BUTTON_NEXT | BUTTON_CANCEL;
$oP->WizardFormButtons($iWizardButtons);
$oP->WizardFormEnd();
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectAServiceSubCategory'));
$oP->add("</div>\n");
}
else
{
$oP->p("Error: Invalid Service: id = $iSvcId");
}
} }
} }
@@ -179,9 +209,11 @@ function SelectServiceSubCategory($oP, $oUserOrg)
* Displays the form for the final step of the UserRequest creation * Displays the form for the final step of the UserRequest creation
* @param WebPage $oP The current web page for the form output * @param WebPage $oP The current web page for the form output
* @param Organization $oUserOrg The organization of the current user * @param Organization $oUserOrg The organization of the current user
* @param integer $iSvcId The identifier of the service (in cal of fall through, when there is only one service)
* @param integer $iSubSvcId The identifier of the sub-service (in cal of fall through, when there is only one sub-service)
* @return void * @return void
*/ */
function RequestCreationForm($oP, $oUserOrg) function RequestCreationForm($oP, $oUserOrg, $iSvcId = null, $iSubSvcId = null)
{ {
$oP->add_script( $oP->add_script(
<<<EOF <<<EOF
@@ -190,7 +222,15 @@ function RequestCreationForm($oP, $oUserOrg)
EOF EOF
); );
$aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS); $aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS);
if ($iSvcId != null)
{
$aParameters['service_id'] = $iSvcId;
}
if ($iSubSvcId != null)
{
$aParameters['servicesubcategory_id'] = $iSubSvcId;
}
// Example: $aList = array('title', 'description', 'impact', 'emergency'); // Example: $aList = array('title', 'description', 'impact', 'emergency');
$aList = explode(',', PORTAL_REQUEST_FORM_ATTRIBUTES); $aList = explode(',', PORTAL_REQUEST_FORM_ATTRIBUTES);
@@ -418,7 +458,7 @@ function ListOpenRequests(WebPage $oP)
$oSearch->AddCondition('caller_id', $iUser); $oSearch->AddCondition('caller_id', $iUser);
} }
$oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey()));
$aZList = array('finalclass', 'title', 'start_date', 'status', 'servicesubcategory_id', 'priority', 'caller_id'); $aZList = explode(',', PORTAL_TICKETS_LIST_ZLIST);
$oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest')); $oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest'));
} }
@@ -439,7 +479,7 @@ function ListResolvedRequests(WebPage $oP)
$oSearch->AddCondition('caller_id', $iUser); $oSearch->AddCondition('caller_id', $iUser);
} }
$oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey())); $oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey()));
$aZList = array('finalclass', 'title', 'start_date', 'status', 'servicesubcategory_id', 'priority', 'caller_id'); $aZList = explode(',', PORTAL_TICKETS_LIST_ZLIST);
$oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest')); $oP->DisplaySet($oSet, $aZList, Dict::S('Portal:NoOpenRequest'));
} }
@@ -450,8 +490,8 @@ function ListResolvedRequests(WebPage $oP)
*/ */
function ListClosedTickets(WebPage $oP) function ListClosedTickets(WebPage $oP)
{ {
$aAttSpecs = array('ref', 'start_date', 'close_date', 'service_id', 'caller_id'); $aAttSpecs = explode(',', PORTAL_TICKETS_SEARCH_CRITERIA);
$aZList = array('title', 'start_date', 'close_date', 'servicesubcategory_id'); $aZList = explode(',', PORTAL_TICKETS_CLOSED_ZLIST);
$oP->DisplaySearchForm('UserRequest', $aAttSpecs, array('operation' => 'show_closed'), 'search_', false /* => not closed */); $oP->DisplaySearchForm('UserRequest', $aAttSpecs, array('operation' => 'show_closed'), 'search_', false /* => not closed */);
@@ -471,10 +511,8 @@ function ListClosedTickets(WebPage $oP)
$oSearch->AddCondition('caller_id', $iUser); $oSearch->AddCondition('caller_id', $iUser);
} }
$oSet1 = new CMDBObjectSet($oSearch); $oSet1 = new CMDBObjectSet($oSearch);
$oP->add("<p>\n");
$oP->add("<h1>".Dict::S('Portal:ClosedRequests')."</h1>\n"); $oP->add("<h1>".Dict::S('Portal:ClosedRequests')."</h1>\n");
$oP->DisplaySet($oSet1, $aZList, Dict::S('Portal:NoClosedRequest')); $oP->DisplaySet($oSet1, $aZList, Dict::S('Portal:NoClosedRequest'));
$oP->add("</p>\n");
} }
@@ -505,7 +543,7 @@ function DisplayObject($oP, $oObj, $oUserOrg)
* @return void * @return void
*/ */
function ShowDetailsRequest(WebPage $oP, $oObj) function ShowDetailsRequest(WebPage $oP, $oObj)
{ {
$sClass = get_class($oObj); $sClass = get_class($oObj);
$bIsEscalateButton = false; $bIsEscalateButton = false;
@@ -559,7 +597,8 @@ function ShowDetailsRequest(WebPage $oP, $oObj)
switch($sClass) switch($sClass)
{ {
case 'UserRequest': case 'UserRequest':
$aAttList = array('col:left'=> array('ref','caller_id','servicesubcategory_id','title','description'),'col:right'=> array('status','priority','start_date','resolution_date','last_update','agent_id')); $aAttList = json_decode(PORTAL_TICKET_DETAILS_ZLIST, true);
switch($oObj->GetState()) switch($oObj->GetState())
{ {
case 'closed': case 'closed':
@@ -879,11 +918,13 @@ try
switch($sOperation) switch($sOperation)
{ {
case 'show_closed': case 'show_closed':
$oP->set_title(Dict::S('Portal:ShowClosed'));
DisplayMainMenu($oP); DisplayMainMenu($oP);
ShowClosedTickets($oP); ShowClosedTickets($oP);
break; break;
case 'create_request': case 'create_request':
$oP->set_title(Dict::S('Portal:CreateNewRequest'));
DisplayMainMenu($oP); DisplayMainMenu($oP);
if (!MetaModel::DBIsReadOnly()) if (!MetaModel::DBIsReadOnly())
{ {
@@ -892,12 +933,14 @@ try
break; break;
case 'details': case 'details':
$oP->set_title(Dict::S('Portal:TitleDetailsFor_Request'));
DisplayMainMenu($oP); DisplayMainMenu($oP);
$oObj = $oP->FindObjectFromArgs(array('UserRequest')); $oObj = $oP->FindObjectFromArgs(array('UserRequest'));
DisplayObject($oP, $oObj, $oUserOrg); DisplayObject($oP, $oObj, $oUserOrg);
break; break;
case 'update_request': case 'update_request':
$oP->set_title(Dict::S('Portal:TitleDetailsFor_Request'));
DisplayMainMenu($oP); DisplayMainMenu($oP);
if (!MetaModel::DBIsReadOnly()) if (!MetaModel::DBIsReadOnly())
{ {
@@ -926,6 +969,7 @@ try
case 'show_ongoing': case 'show_ongoing':
default: default:
$oP->set_title(Dict::S('Portal:ShowOngoing'));
DisplayMainMenu($oP); DisplayMainMenu($oP);
ShowOngoingTickets($oP); ShowOngoingTickets($oP);
} }

View File

@@ -173,6 +173,20 @@ class ModuleDiscovery
protected static function DependencyIsResolved($sDepString, $aOrderedModules) protected static function DependencyIsResolved($sDepString, $aOrderedModules)
{ {
$bResult = false; $bResult = false;
$aModuleVersions = array();
// Separate the module names from their version for an easier comparison later
foreach($aOrderedModules as $sModuleId)
{
if (preg_match('|^([^/]+)/(.*)$|', $sModuleId, $aMatches))
{
$aModuleVersions[$aMatches[1]] = $aMatches[2];
}
else
{
// No version number found, assume 1.0.0
$aModuleVersions[$sModuleId] = '1.0.0';
}
}
if (preg_match_all('/([^\(\)&| ]+)/', $sDepString, $aMatches)) if (preg_match_all('/([^\(\)&| ]+)/', $sDepString, $aMatches))
{ {
$aReplacements = array(); $aReplacements = array();
@@ -180,17 +194,38 @@ class ModuleDiscovery
{ {
foreach($aMatch as $sModuleId) foreach($aMatch as $sModuleId)
{ {
if (in_array($sModuleId, $aOrderedModules)) // $sModuleId in the dependency string is made of a <name>/<optional_operator><version>
// where the operator is < <= = > >= (by default >=)
if(preg_match('|^([^/]+)/(<?>?=?)([^><=]+)$|', $sModuleId, $aModuleMatches))
{ {
// module is present $sModuleName = $aModuleMatches[1];
$aReplacements[$sModuleId] = '(true)'; // Add parentheses to protect against invalid condition causing $sOperator = $aModuleMatches[2];
// a function call that results in a runtime fatal error if ($sOperator == '')
} {
else $sOperator = '>=';
{ }
// module is not present $sExpectedVersion = $aModuleMatches[3];
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing if (array_key_exists($sModuleName, $aModuleVersions))
// a function call that results in a runtime fatal error {
// module is present, check the version
$sCurrentVersion = $aModuleVersions[$sModuleName];
if (version_compare($sCurrentVersion, $sExpectedVersion, $sOperator))
{
$aReplacements[$sModuleId] = '(true)'; // Add parentheses to protect against invalid condition causing
// a function call that results in a runtime fatal error
}
else
{
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
// a function call that results in a runtime fatal error
}
}
else
{
// module is not present
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
// a function call that results in a runtime fatal error
}
} }
} }
} }

View File

@@ -237,6 +237,7 @@ if (!empty($sExpression))
header("Cache-control:", true); header("Cache-control:", true);
$sFields = implode(',', $aFields); $sFields = implode(',', $aFields);
$oP->add_style('table br {mso-data-placement:same-cell;}'); // Trick for Excel: keep line breaks inside the same cell !
cmdbAbstractObject::DisplaySetAsHTMLSpreadsheet($oP, $oSet, array('fields' => $sFields, 'fields_advanced' => $bFieldsAdvanced, 'localize_values' => $bLocalize)); cmdbAbstractObject::DisplaySetAsHTMLSpreadsheet($oP, $oSet, array('fields' => $sFields, 'fields_advanced' => $bFieldsAdvanced, 'localize_values' => $bLocalize));
break; break;