mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 15:34:12 +01:00
Compare commits
32 Commits
feature/78
...
support/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06e389f14c | ||
|
|
e90f4e1232 | ||
|
|
474df98dfa | ||
|
|
ce88d10766 | ||
|
|
225eab9bd3 | ||
|
|
42b0a8c3cb | ||
|
|
484fa42113 | ||
|
|
5c1149ac68 | ||
|
|
1dbb94a2e1 | ||
|
|
df1869dfe3 | ||
|
|
22ee1cd6f4 | ||
|
|
0b14bf605c | ||
|
|
02717360d0 | ||
|
|
230710eb04 | ||
|
|
6581c02301 | ||
|
|
f925a21735 | ||
|
|
8796e5fa74 | ||
|
|
249dd03b18 | ||
|
|
94ba2c3c1c | ||
|
|
7ec9022bd7 | ||
|
|
7ba2cf59de | ||
|
|
fdacbf6d0f | ||
|
|
580de372e0 | ||
|
|
0faa33a0e5 | ||
|
|
1aff819f8f | ||
|
|
0ac9fce207 | ||
|
|
8a8de2bcc3 | ||
|
|
3b4ff79ea3 | ||
|
|
0fcbc040fd | ||
|
|
ae6e0c5242 | ||
|
|
1ce8046c46 | ||
|
|
56eba6de4c |
@@ -240,6 +240,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sTip .= Dict::S('Core:Synchro:LastSynchro').'<br/>'.$aStruct['last_synchro']."</p>";
|
||||
}
|
||||
$sSynchroIcon = ' <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' }} } );");
|
||||
}
|
||||
|
||||
@@ -431,15 +432,28 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
if (count($aTriggers) > 0)
|
||||
{
|
||||
// Display notifications regarding the object
|
||||
$iId = $this->GetKey();
|
||||
$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");
|
||||
$oNotifSet = new DBObjectSet($oNotifSearch);
|
||||
$sCount = ($oNotifSet->Count() > 0) ? ' ('.$oNotifSet->Count().')' : '';
|
||||
$aNotifSearches = array();
|
||||
$iNotifsCount = 0;
|
||||
$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);
|
||||
$oBlock = new DisplayBlock($oNotifSearch, 'list', false);
|
||||
$oBlock->Display($oPage, 'notifications', array('menu' => false));
|
||||
|
||||
foreach($aNotificationClasses as $sNotifClass)
|
||||
{
|
||||
|
||||
$oPage->p(MetaModel::GetClassIcon($sNotifClass, true).' '.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>';
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCodeEx);
|
||||
|
||||
@@ -231,7 +231,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)
|
||||
|
||||
@@ -1059,7 +1059,7 @@ class DashletBadge extends Dashlet
|
||||
|
||||
|
||||
$oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']);
|
||||
ksort($aClasses);
|
||||
asort($aClasses);
|
||||
$aValues = array();
|
||||
foreach($aClasses as $sClass => $sClass)
|
||||
{
|
||||
|
||||
@@ -64,6 +64,7 @@ class PortalWebPage extends NiceWebPage
|
||||
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sAppContext = addslashes($oAppContext->GetForLink());
|
||||
$this->add_dict_entry('UI:FillAllMandatoryFields');
|
||||
if ($sAlternateStyleSheet != '')
|
||||
{
|
||||
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
</itoptab>
|
||||
<itoptab name="UI:NotificationsMenu:Actions">
|
||||
<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>
|
||||
</itoptabs>
|
||||
|
||||
@@ -869,6 +869,60 @@ class utils
|
||||
static public function GetSafeId($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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -140,7 +140,7 @@ class AsyncSendEmail extends AsyncTask
|
||||
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 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 AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
@@ -2078,7 +2078,7 @@ class AttributeEmailAddress extends AttributeString
|
||||
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 "^[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)
|
||||
@@ -3360,26 +3360,26 @@ class AttributeBlob extends AttributeDefinition
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!isset($aCols[$sPrefix]))
|
||||
if (!array_key_exists($sPrefix, $aCols))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
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));
|
||||
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));
|
||||
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);
|
||||
return $value;
|
||||
@@ -4127,19 +4127,19 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!isset($aCols[$sPrefix]))
|
||||
if (!array_key_exists($sPrefix, $aCols))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
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));
|
||||
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);
|
||||
return $value;
|
||||
@@ -4506,7 +4506,7 @@ class AttributeComputedFieldVoid extends AttributeDefinition
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array();
|
||||
return array("="=>"equals", "!="=>"differs from");
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
|
||||
@@ -296,10 +296,17 @@ class BulkChange
|
||||
$oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass());
|
||||
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
|
||||
{
|
||||
// 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);
|
||||
if ($sForeignAttCode == 'id')
|
||||
{
|
||||
$value = (int) $aRowData[$iCol];
|
||||
}
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
|
||||
$oMyChangeOp->Set("objkey", $objkey);
|
||||
$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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -162,8 +162,7 @@ class ormStopWatch
|
||||
}
|
||||
else
|
||||
{
|
||||
$iElapsedTemp = ''; //$this->ComputeDuration($oHostObject, $oAttDef, $this->iLastStart, time());
|
||||
$aProperties['Elapsed'] = $this->iTimeSpent.' + '.$iElapsedTemp.' s + <img src="../images/indicator.gif">';
|
||||
$aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
|
||||
}
|
||||
|
||||
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
|
||||
@@ -183,7 +182,7 @@ class ormStopWatch
|
||||
}
|
||||
$aProperties[$iPercent.'%'] = $sThresholdDesc;
|
||||
}
|
||||
$sRes = "<TABLE class=\"listResults\">";
|
||||
$sRes = "<TABLE>";
|
||||
$sRes .= "<TBODY>";
|
||||
foreach ($aProperties as $sProperty => $sValue)
|
||||
{
|
||||
@@ -387,9 +386,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$aList = array();
|
||||
foreach (MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
$aList = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
@@ -398,8 +397,8 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
{
|
||||
$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()";
|
||||
//echo $sExpression."<br/>\n";
|
||||
$sNow = date('Y-m-d H:i:s');
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '$sNow'";
|
||||
$oFilter = DBObjectSearch::FromOQL($sExpression);
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
|
||||
@@ -407,7 +406,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
|
||||
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
|
||||
|
||||
// Execute planned actions
|
||||
//
|
||||
@@ -416,7 +414,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$sVerb = $aActionData['verb'];
|
||||
$aParams = $aActionData['params'];
|
||||
$sParams = implode(', ', $aParams);
|
||||
//echo "Calling: $sVerb($sParams)<br/>\n";
|
||||
$aCallSpec = array($oObj, $sVerb);
|
||||
call_user_func_array($aCallSpec, $aParams);
|
||||
}
|
||||
@@ -438,12 +435,12 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
// Activate any existing trigger
|
||||
//
|
||||
$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"),
|
||||
array(), // order by
|
||||
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
|
||||
);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
while ($oTrigger = $oTriggerSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($oObj->ToArgs('this'));
|
||||
}
|
||||
@@ -454,9 +451,6 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
}
|
||||
|
||||
$iProcessed = count($aList);
|
||||
return "Triggered $iProcessed threshold(s)";
|
||||
return "Triggered $iProcessed threshold(s):".implode(", ", $aList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -350,7 +350,8 @@ EOF
|
||||
$oPage->add('</span>');
|
||||
$oPage->add('<div style="clear:both"></div>');
|
||||
$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"> <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"> <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('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
|
||||
@@ -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_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"]}');
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -350,7 +350,8 @@ EOF
|
||||
$oPage->add('</span>');
|
||||
$oPage->add('<div style="clear:both"></div>');
|
||||
$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"> <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"> <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('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
|
||||
@@ -1452,28 +1452,31 @@
|
||||
$sUserString = CMDBChange::GetCurrentUserName();
|
||||
$oMyChange->Set("userinfo", $sUserString."(automatic resolution)");
|
||||
$iChangeId = $oMyChange->DBInsert();
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
//automatically resolve child requests
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
if ( $oRequest->Get('status') != 'resolved')
|
||||
{
|
||||
$oRequest->set('servicesubcategory_id',$this->Get('servicesubcategory_id'));
|
||||
$oRequest->set('service_id',$this->Get('service_id'));
|
||||
$oRequest->set('team_id',$this->Get('team_id'));
|
||||
$oRequest->set('agent_id',$this->Get('agent_id'));
|
||||
$oRequest->set('resolution_code',$this->Get('resolution_code'));
|
||||
$oRequest->set('solution','Automatically resolved by incident:[[Incident:'.$this->Get('ref').']]');
|
||||
$oRequest->ApplyStimulus('ev_autoresolve');
|
||||
$oRequest->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
if (MetaModel::IsValidClass('UserRequest'))
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
//automatically resolve child requests
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
if ( $oRequest->Get('status') != 'resolved')
|
||||
{
|
||||
$oRequest->set('servicesubcategory_id',$this->Get('servicesubcategory_id'));
|
||||
$oRequest->set('service_id',$this->Get('service_id'));
|
||||
$oRequest->set('team_id',$this->Get('team_id'));
|
||||
$oRequest->set('agent_id',$this->Get('agent_id'));
|
||||
$oRequest->set('resolution_code',$this->Get('resolution_code'));
|
||||
$oRequest->set('solution','Automatically resolved by incident:[[Incident:'.$this->Get('ref').']]');
|
||||
$oRequest->ApplyStimulus('ev_autoresolve');
|
||||
$oRequest->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//automatically resolve child incidents
|
||||
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";
|
||||
@@ -1507,6 +1510,8 @@
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildRequestLog()
|
||||
{
|
||||
if (!MetaModel::IsValidClass('UserRequest')) return true; // Do nothing
|
||||
|
||||
$sLogPublic = utils::ReadPostedParam('attr_public_log', null,false,'raw_data');
|
||||
if ( $sLogPublic != null)
|
||||
{
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<action id="ev_reassign" 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_pending" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:UserRequest">
|
||||
|
||||
@@ -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_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"]}');
|
||||
?>
|
||||
|
||||
@@ -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_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"]}');
|
||||
?>
|
||||
|
||||
@@ -782,6 +782,7 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
|
||||
'Portal:Refresh' => 'Neu laden',
|
||||
'Portal:Back' => 'Zurück',
|
||||
'Portal:WelcomeUserOrg' => 'Wilkommen %1$s, von %2$s',
|
||||
'Portal:TitleDetailsFor_Request' => 'Deails für Benutzeranfrage',
|
||||
'Portal:ShowOngoing' => 'Zeige offene Requests',
|
||||
'Portal:ShowClosed' => 'Zeige geschlossene Requests',
|
||||
'Portal:CreateNewRequest' => 'Einen neuen Request erstellen',
|
||||
|
||||
@@ -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:ObjectCouldNotBeWritten' => 'The object could not be written: %1$s',
|
||||
'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: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:Back' => 'Back',
|
||||
'Portal:WelcomeUserOrg' => 'Welcome %1$s, from %2$s',
|
||||
'Portal:TitleDetailsFor_Request' => 'Details for request',
|
||||
'Portal:ShowOngoing' => 'Show open requests',
|
||||
'Portal:ShowClosed' => 'Show closed requests',
|
||||
'Portal:CreateNewRequest' => 'Create a new request',
|
||||
|
||||
@@ -943,6 +943,7 @@ Cuando se asocien con un disparador, cada acción recibe un número de "orden",
|
||||
'Portal:Refresh' => 'Actualizar',
|
||||
'Portal:Back' => 'Atrás',
|
||||
'Portal:WelcomeUserOrg' => 'Bienvenido %1$s, de %2$s',
|
||||
'Portal:TitleDetailsFor_Request' => 'Detalles de la Solicitud',
|
||||
'Portal:ShowOngoing' => 'Mostrar Requerimientos Abiertos',
|
||||
'Portal:ShowClosed' => 'Mostrar Requerimientos Cerrados',
|
||||
'Portal:CreateNewRequest' => 'Crear Requerimiento',
|
||||
|
||||
@@ -786,6 +786,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'Portal:Refresh' => 'Rafraîchir',
|
||||
'Portal:Back' => 'Retour',
|
||||
'Portal:WelcomeUserOrg' => 'Bienvenue %1$s (%2$s)',
|
||||
'Portal:TitleDetailsFor_Request' => 'Détail de la requête',
|
||||
'Portal:ShowOngoing' => 'Requêtes en cours',
|
||||
'Portal:ShowClosed' => 'Requêtes fermées',
|
||||
'Portal:CreateNewRequest' => 'Créer une nouvelle requête',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ jQuery.extend(
|
||||
var fileId = 'jUploadFile' + id;
|
||||
var form = jQuery('<form action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
|
||||
var oldElement = jQuery('#' + fileElementId);
|
||||
var newElement = jQuery(oldElement).clone();
|
||||
var newElement = jQuery(oldElement).clone(true);
|
||||
jQuery(oldElement).attr('id', fileId);
|
||||
jQuery(oldElement).before(newElement);
|
||||
jQuery(oldElement).appendTo(form);
|
||||
@@ -131,12 +131,12 @@ jQuery.extend(
|
||||
jQuery.handleError(s, xml, null, e);
|
||||
}
|
||||
|
||||
}, 100)
|
||||
}, 100);
|
||||
|
||||
xml = null
|
||||
xml = null;
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
// Timeout checker
|
||||
if ( s.timeout > 0 )
|
||||
{
|
||||
@@ -197,7 +197,9 @@ jQuery.extend({
|
||||
s.error( xhr, status, e );
|
||||
// If we have some XML response text (e.g. from an AJAX call) then log it in the console
|
||||
else if(xhr.responseText)
|
||||
console.log(xhr.responseText);
|
||||
{
|
||||
//console.log(xhr.responseText);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -438,59 +438,70 @@ function sprintf(format, etc) {
|
||||
|
||||
this.construct = function(settings) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
||||
return this.each(function() {
|
||||
|
||||
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());
|
||||
setPageSize(table,config.selectedSize, false);
|
||||
restoreParams(table, config);
|
||||
|
||||
//$(this).trigger("appendCache"); // Load the data
|
||||
//console.log($.tablesorterPager);
|
||||
applySelection(table);
|
||||
config.selectedSize = parseInt($(".pagesize",pager).val());
|
||||
|
||||
$('.gotopage',pager).click(function() {
|
||||
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);
|
||||
});
|
||||
setPageSize(table,config.selectedSize, false);
|
||||
restoreParams(table, config);
|
||||
|
||||
$(table).bind('load_selection', function() {
|
||||
loadSelection(table, pager);
|
||||
//$(this).trigger("appendCache"); // Load the data
|
||||
//console.log($.tablesorterPager);
|
||||
applySelection(table);
|
||||
});
|
||||
$(table).bind('check_all', function() {
|
||||
checkAll(table, pager, true);
|
||||
});
|
||||
|
||||
$('.gotopage',pager).click(function() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -126,13 +126,7 @@ class Swift_Transport_MailTransport implements Swift_Transport
|
||||
$toHeader = $message->getHeaders()->get('To');
|
||||
$subjectHeader = $message->getHeaders()->get('Subject');
|
||||
|
||||
if (!$toHeader)
|
||||
{
|
||||
throw new Swift_TransportException(
|
||||
'Cannot send message without a recipient'
|
||||
);
|
||||
}
|
||||
$to = $toHeader->getFieldBody();
|
||||
$to = $toHeader ? $toHeader->getFieldBody() : '';
|
||||
$subject = $subjectHeader ? $subjectHeader->getFieldBody() : '';
|
||||
|
||||
$reversePath = $this->_getReversePath($message);
|
||||
@@ -143,7 +137,10 @@ class Swift_Transport_MailTransport implements Swift_Transport
|
||||
|
||||
$messageStr = $message->toString();
|
||||
|
||||
$message->getHeaders()->set($toHeader);
|
||||
if ($toHeader)
|
||||
{
|
||||
$message->getHeaders()->set($toHeader);
|
||||
}
|
||||
$message->getHeaders()->set($subjectHeader);
|
||||
|
||||
//Separate headers from body
|
||||
|
||||
20
pages/UI.php
20
pages/UI.php
@@ -938,9 +938,9 @@ try
|
||||
$id = utils::ReadParam('id', '');
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
$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
|
||||
@@ -957,11 +957,21 @@ try
|
||||
{
|
||||
$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)
|
||||
cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');
|
||||
|
||||
@@ -936,6 +936,7 @@ EOF
|
||||
|
||||
case 'shortcut_delete_go':
|
||||
$oSearch = new DBObjectSearch('Shortcut');
|
||||
$oSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$aShortcuts = utils::ReadMultipleSelection($oSearch);
|
||||
foreach ($aShortcuts as $iShortcut)
|
||||
{
|
||||
|
||||
182
portal/index.php
182
portal/index.php
@@ -84,33 +84,43 @@ function SelectServiceCategory($oP, $oUserOrg)
|
||||
{
|
||||
$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->AllowAllData(); // In case the user has the rights on his org only
|
||||
$oSet = new CMDBObjectSet($oSearch, array(), array('org_id' => $oUserOrg->GetKey()));
|
||||
while($oService = $oSet->Fetch())
|
||||
if ($oSet->Count() == 1)
|
||||
{
|
||||
$id = $oService->GetKey();
|
||||
$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>");
|
||||
$oService = $oSet->Fetch();
|
||||
$iSvcCategory = $oService->GetKey();
|
||||
// Only one Category, skip this step in the wizard
|
||||
SelectServiceSubCategory($oP, $oUserOrg, $iSvcCategory);
|
||||
}
|
||||
$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("<input type=\"hidden\" name=\"operation\" value=\"create_request\">");
|
||||
$oP->WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL);
|
||||
$oP->WizardFormEnd();
|
||||
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectOneService'));
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<h1 id=\"select_category\">".Dict::S('Portal:SelectService')."</h1>\n");
|
||||
$oP->add("<table>\n");
|
||||
while($oService = $oSet->Fetch())
|
||||
{
|
||||
$id = $oService->GetKey();
|
||||
$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'
|
||||
* @param WebPage $oP Web page for the form output
|
||||
* @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
|
||||
*/
|
||||
|
||||
function SelectServiceSubCategory($oP, $oUserOrg)
|
||||
function SelectServiceSubCategory($oP, $oUserOrg, $iSvcId = null)
|
||||
{
|
||||
$aParameters = $oP->ReadAllParams(PORTAL_ALL_PARAMS);
|
||||
|
||||
$iSvcId = $aParameters['service_id'];
|
||||
$iWizardButtons = 0;
|
||||
if ($iSvcId == null)
|
||||
{
|
||||
$iSvcId = $aParameters['service_id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$aParameters['service_id'] = $iSvcId;
|
||||
$iWizardButtons = BUTTON_NEXT;
|
||||
}
|
||||
$iDefaultSubSvcId = isset($aParameters['servicesubcategory_id']) ? $aParameters['servicesubcategory_id'] : 0;
|
||||
|
||||
$iDefaultWizNext = 2;
|
||||
@@ -133,45 +152,56 @@ function SelectServiceSubCategory($oP, $oUserOrg)
|
||||
$oSearch = DBObjectSearch::FromOQL(PORTAL_SERVICE_SUBCATEGORY_QUERY);
|
||||
$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()));
|
||||
$oServiceCategory = MetaModel::GetObject('Service', $iSvcId, false, true /* allow all data*/);
|
||||
if (is_object($oServiceCategory))
|
||||
if ($oSet->Count() == 1)
|
||||
{
|
||||
$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\">");
|
||||
$oP->WizardFormButtons(BUTTON_BACK | BUTTON_NEXT | BUTTON_CANCEL);
|
||||
$oP->WizardFormEnd();
|
||||
$oP->WizardCheckSelectionOnSubmit(Dict::S('Portal:PleaseSelectAServiceSubCategory'));
|
||||
$oP->add("</div>\n");
|
||||
// Only one sub service, skip this step of the wizard
|
||||
$oSubService = $oSet->Fetch();
|
||||
$iSubSvdId = $oSubService->GetKey();
|
||||
RequestCreationForm($oP, $oUserOrg, $iSvcId, $iSubSvdId);
|
||||
}
|
||||
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
|
||||
* @param WebPage $oP The current web page for the form output
|
||||
* @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
|
||||
*/
|
||||
function RequestCreationForm($oP, $oUserOrg)
|
||||
function RequestCreationForm($oP, $oUserOrg, $iSvcId = null, $iSubSvcId = null)
|
||||
{
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
@@ -190,7 +222,15 @@ function RequestCreationForm($oP, $oUserOrg)
|
||||
EOF
|
||||
);
|
||||
$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');
|
||||
$aList = explode(',', PORTAL_REQUEST_FORM_ATTRIBUTES);
|
||||
|
||||
@@ -418,7 +458,7 @@ function ListOpenRequests(WebPage $oP)
|
||||
$oSearch->AddCondition('caller_id', $iUser);
|
||||
}
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -439,7 +479,7 @@ function ListResolvedRequests(WebPage $oP)
|
||||
$oSearch->AddCondition('caller_id', $iUser);
|
||||
}
|
||||
$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'));
|
||||
}
|
||||
|
||||
@@ -450,8 +490,8 @@ function ListResolvedRequests(WebPage $oP)
|
||||
*/
|
||||
function ListClosedTickets(WebPage $oP)
|
||||
{
|
||||
$aAttSpecs = array('ref', 'start_date', 'close_date', 'service_id', 'caller_id');
|
||||
$aZList = array('title', 'start_date', 'close_date', 'servicesubcategory_id');
|
||||
$aAttSpecs = explode(',', PORTAL_TICKETS_SEARCH_CRITERIA);
|
||||
$aZList = explode(',', PORTAL_TICKETS_CLOSED_ZLIST);
|
||||
|
||||
$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);
|
||||
}
|
||||
$oSet1 = new CMDBObjectSet($oSearch);
|
||||
$oP->add("<p>\n");
|
||||
$oP->add("<h1>".Dict::S('Portal:ClosedRequests')."</h1>\n");
|
||||
$oP->DisplaySet($oSet1, $aZList, Dict::S('Portal:NoClosedRequest'));
|
||||
$oP->add("</p>\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -505,7 +543,7 @@ function DisplayObject($oP, $oObj, $oUserOrg)
|
||||
* @return void
|
||||
*/
|
||||
function ShowDetailsRequest(WebPage $oP, $oObj)
|
||||
{
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$bIsEscalateButton = false;
|
||||
@@ -559,7 +597,8 @@ function ShowDetailsRequest(WebPage $oP, $oObj)
|
||||
switch($sClass)
|
||||
{
|
||||
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())
|
||||
{
|
||||
case 'closed':
|
||||
@@ -879,11 +918,13 @@ try
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'show_closed':
|
||||
$oP->set_title(Dict::S('Portal:ShowClosed'));
|
||||
DisplayMainMenu($oP);
|
||||
ShowClosedTickets($oP);
|
||||
break;
|
||||
|
||||
case 'create_request':
|
||||
$oP->set_title(Dict::S('Portal:CreateNewRequest'));
|
||||
DisplayMainMenu($oP);
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
@@ -892,12 +933,14 @@ try
|
||||
break;
|
||||
|
||||
case 'details':
|
||||
$oP->set_title(Dict::S('Portal:TitleDetailsFor_Request'));
|
||||
DisplayMainMenu($oP);
|
||||
$oObj = $oP->FindObjectFromArgs(array('UserRequest'));
|
||||
DisplayObject($oP, $oObj, $oUserOrg);
|
||||
break;
|
||||
|
||||
case 'update_request':
|
||||
$oP->set_title(Dict::S('Portal:TitleDetailsFor_Request'));
|
||||
DisplayMainMenu($oP);
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
@@ -926,6 +969,7 @@ try
|
||||
|
||||
case 'show_ongoing':
|
||||
default:
|
||||
$oP->set_title(Dict::S('Portal:ShowOngoing'));
|
||||
DisplayMainMenu($oP);
|
||||
ShowOngoingTickets($oP);
|
||||
}
|
||||
|
||||
@@ -173,6 +173,20 @@ class ModuleDiscovery
|
||||
protected static function DependencyIsResolved($sDepString, $aOrderedModules)
|
||||
{
|
||||
$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))
|
||||
{
|
||||
$aReplacements = array();
|
||||
@@ -180,17 +194,38 @@ class ModuleDiscovery
|
||||
{
|
||||
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
|
||||
$aReplacements[$sModuleId] = '(true)'; // 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
|
||||
$sModuleName = $aModuleMatches[1];
|
||||
$sOperator = $aModuleMatches[2];
|
||||
if ($sOperator == '')
|
||||
{
|
||||
$sOperator = '>=';
|
||||
}
|
||||
$sExpectedVersion = $aModuleMatches[3];
|
||||
if (array_key_exists($sModuleName, $aModuleVersions))
|
||||
{
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +237,7 @@ if (!empty($sExpression))
|
||||
header("Cache-control:", true);
|
||||
|
||||
$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));
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user