mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Synchro Data Sources Implementation on going...
SVN:trunk[1107]
This commit is contained in:
@@ -91,9 +91,58 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
|
||||
$oBlock = new MenuBlock($oSingletonFilter, 'popup', false);
|
||||
$oBlock->Display($oPage, -1);
|
||||
|
||||
// Master data sources
|
||||
$oReplicaSet = $this->GetMasterReplica();
|
||||
$bSynchronized = false;
|
||||
$bCreated = false;
|
||||
$bCanBeDeleted = false;
|
||||
$aMasterSources = array();
|
||||
if ($oReplicaSet->Count() > 0)
|
||||
{
|
||||
$bSynchronized = true;
|
||||
$sTip = "<p>The object is synchronized with an external data source</p>";
|
||||
while($aData = $oReplicaSet->FetchAssoc())
|
||||
{
|
||||
$sApplicationURL = $aData['datasource']->GetApplicationUrl($this, $aData['replica']);
|
||||
$sLink = "<a href=\"$sApplicationURL\" target=\"_blank\">".$aData['datasource']->GetName()."</a>";
|
||||
if ($aData['replica']->Get('status_dest_creator') == 1)
|
||||
{
|
||||
$sTip .= "<p>The object was <b>created</b> by the external data source $sLink</p>";
|
||||
$bCreated = true;
|
||||
}
|
||||
if ($bCreated)
|
||||
{
|
||||
$sDeletePolicy = $aData['datasource']->Get('delete_policy');
|
||||
if (($sDeletePolicy == 'delete') || ($sDeletePolicy == 'update_then_delete'))
|
||||
{
|
||||
$bCanBeDeleted = true;
|
||||
$sTip .= "<p>The object <b>can be deleted</b> by the external data source $sLink</p>";
|
||||
}
|
||||
}
|
||||
$aMasterSources[$aData['datasource']->GetKey()]['datasource'] = $aData['datasource'];
|
||||
$aMasterSources[$aData['datasource']->GetKey()]['url'] = $sLink;
|
||||
}
|
||||
}
|
||||
|
||||
$sSynchroIcon = '';
|
||||
if ($bSynchronized)
|
||||
{
|
||||
$sTip .= "<p><b>List of data sources:</b></p>";
|
||||
foreach($aMasterSources as $aStruct)
|
||||
{
|
||||
$oDataSource = $aStruct['datasource'];
|
||||
$sLink = $aStruct['url'];
|
||||
$sTip .= "<p style=\"white-space:nowrap\">".$oDataSource->GetIcon(true, 'style="vertical-align:middle"')." $sLink</p>";
|
||||
}
|
||||
$sSynchroIcon = ' <img style="vertical-align:middle;" id="synchro_icon" src="../images/locked.png"/>';
|
||||
$oPage->add_ready_script("$('#synchro_icon').qtip( { content: '$sTip', show: 'mouseover', hide: 'unfocus', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
$oPage->add("<div class=\"page_header\"><h1>".$this->GetIcon()." \n");
|
||||
$oPage->add(MetaModel::GetName(get_class($this)).": <span class=\"hilite\">".$this->GetName()."</span></h1>\n");
|
||||
$oPage->add(MetaModel::GetName(get_class($this)).": <span class=\"hilite\">".$this->GetName()."</span>$sSynchroIcon</h1>\n");
|
||||
$oPage->add("</div>\n");
|
||||
|
||||
}
|
||||
|
||||
function DisplayBareHistory(WebPage $oPage, $bEditMode = false)
|
||||
@@ -267,6 +316,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
// all the remaining attributes that are not external fields
|
||||
$sHtml = '';
|
||||
$aDetails = array();
|
||||
$iInputId = 0;
|
||||
foreach($aDetailsStruct as $sTab => $aCols )
|
||||
{
|
||||
$aDetails[$sTab] = array();
|
||||
@@ -310,8 +360,25 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$val = $this->GetFieldAsHtml($sClass, $sAttCode, $sStateAttCode);
|
||||
if ($val != null)
|
||||
{
|
||||
// Check if the attribute is not mastered by a synchro...
|
||||
$aReasons = array();
|
||||
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = '';
|
||||
if ($iSynchroFlags & OPT_ATT_READONLY)
|
||||
{
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
$val['value'] .= $sSynchroIcon;
|
||||
// The field is visible, add it to the current column
|
||||
$aDetails[$sTab][$sColIndex][] = $val;
|
||||
$iInputId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1305,8 +1372,7 @@ EOF
|
||||
$aVal = array('label' => $oAttDef->GetLabel(), 'value' => $sHTMLValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iFlags = $this->GetAttributeFlags($sAttCode);
|
||||
{
|
||||
$sInputId = $this->m_iFormId.'_'.$sAttCode;
|
||||
if ($iFlags & OPT_ATT_HIDDEN)
|
||||
{
|
||||
@@ -1318,8 +1384,24 @@ EOF
|
||||
{
|
||||
if ($iFlags & OPT_ATT_READONLY)
|
||||
{
|
||||
|
||||
// Check if the attribute is not read-only becuase of a synchro...
|
||||
$aReasons = array();
|
||||
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = '';
|
||||
if ($iSynchroFlags & OPT_ATT_READONLY)
|
||||
{
|
||||
$sSynchroIcon = " <img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
$sTip .= "<p>Synchronized with {$aRow['name']} - {$aRow['description']}</p>";
|
||||
}
|
||||
$oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = $this->GetAsHTML($sAttCode);
|
||||
$sHTMLValue = $this->GetAsHTML($sAttCode).$sSynchroIcon;
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->add_linked_script("../js/swfobject.js");
|
||||
$this->add_linked_script("../js/ckeditor/ckeditor.js");
|
||||
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
try
|
||||
|
||||
@@ -50,6 +50,7 @@ abstract class DBObject
|
||||
|
||||
private $m_bFullyLoaded = false; // Compound objects can be partially loaded
|
||||
private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode
|
||||
protected $m_oMasterReplicaSet = null; // Set of SynchroReplica related to this object
|
||||
|
||||
// Use the MetaModel::NewObject to build an object (do we have to force it?)
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aExtendedDataSpec = null)
|
||||
@@ -645,7 +646,9 @@ abstract class DBObject
|
||||
{
|
||||
$iFlags = MetaModel::GetAttributeFlags(get_class($this), $this->Get($sStateAttCode), $sAttCode);
|
||||
}
|
||||
return $iFlags;
|
||||
$aReasons = array();
|
||||
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
return $iFlags | $iSynchroFlags; // Combine both sets of flags
|
||||
}
|
||||
|
||||
// check if the given (or current) value is suitable for the attribute
|
||||
@@ -1402,6 +1405,50 @@ abstract class DBObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the synchro replica related to this object
|
||||
* @param none
|
||||
* @return DBObjectSet Set with two columns: R=SynchroReplica S=SynchroDataSource
|
||||
*/
|
||||
public function GetMasterReplica()
|
||||
{
|
||||
if ($this->m_oMasterReplicaSet == null)
|
||||
{
|
||||
$aParentClasses = MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL);
|
||||
$sClassesList = "'".implode("','", $aParentClasses)."'";
|
||||
$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE datasource.scope_class IN ($sClassesList) AND replica.dest_id = :dest_id";
|
||||
$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_id' => $this->GetKey()));
|
||||
$this->m_oMasterReplicaSet = $oReplicaSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_oMasterReplicaSet->Rewind();
|
||||
}
|
||||
return $this->m_oMasterReplicaSet;
|
||||
}
|
||||
|
||||
public function GetSynchroReplicaFlags($sAttCode, &$aReason)
|
||||
{
|
||||
$iFlags = OPT_ATT_NORMAL;
|
||||
$oSet = $this->GetMasterReplica();
|
||||
while($aData = $oSet->FetchAssoc())
|
||||
{
|
||||
$oReplica = $aData['replica'];
|
||||
$oSource = $aData['datasource'];
|
||||
$oAttrSet = $oSource->Get('attribute_list');
|
||||
while($oSyncAttr = $oAttrSet->Fetch())
|
||||
{
|
||||
if (($oSyncAttr->Get('attcode') == $sAttCode) && ($oSyncAttr->Get('update') == 1) && ($oSyncAttr->Get('update_policy') == 'master_locked'))
|
||||
{
|
||||
$iFlags |= OPT_ATT_READONLY;
|
||||
$sUrl = $oSource->GetApplicationUrl($this, $oReplica);
|
||||
$aReason[] = array('name' => $oSource->GetName(), 'description' => $oSource->Get('description'), 'url_application' => $sUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $iFlags;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
images/transp-lock.png
Normal file
BIN
images/transp-lock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 390 B |
16
js/jquery.qtip-1.0.min.js
vendored
Normal file
16
js/jquery.qtip-1.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -75,9 +75,15 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeDuration("delete_policy_retention", array("allowed_values"=>null, "sql"=>"delete_policy_retention", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSet("attribute_list", array("linked_class"=>"SynchroAttribute", "ext_key_to_me"=>"sync_source_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array())));
|
||||
// Not used yet !
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("user_delete_policy", array("allowed_values"=>new ValueSetEnum('never,depends,always'), "sql"=>"user_delete_policy", "default_value"=>"always", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeURL("url_icon", array("allowed_values"=>null, "sql"=>"url_icon", "default_value"=>null, "is_null_allowed"=>true, "target"=> '_top', "depends_on"=>array())));
|
||||
// The field below is not a real URL since it can contain placeholders like $replica->primary_key$ which are not syntactically allowed in a real URL
|
||||
MetaModel::Init_AddAttribute(new AttributeString("url_application", array("allowed_values"=>null, "sql"=>"url_application", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'scope_class', /*'scope_restriction', */'status', 'user_id', 'full_load_periodicity', 'reconciliation_policy', 'action_on_zero', 'action_on_one', 'action_on_multiple', 'delete_policy', 'delete_policy_update', 'delete_policy_retention' /*'attribute_list'*/)); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'description', 'url_icon', 'url_application', 'scope_class', /*'scope_restriction', */'status', 'user_id', 'full_load_periodicity', 'reconciliation_policy', 'action_on_zero', 'action_on_one', 'action_on_multiple', 'delete_policy', 'delete_policy_update', 'delete_policy_retention' /*'attribute_list'*/)); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('scope_class', 'status', 'user_id', 'full_load_periodicity')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'scope_class', 'user_id')); // Criteria of the std search form
|
||||
@@ -168,6 +174,7 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
$aValues[] = $aRow;
|
||||
}
|
||||
}
|
||||
$oPage->p(Dict::Format('Class:SynchroDataSource:DataTable', $this->GetDataTable()));
|
||||
$oPage->Table($aAttribs, $aValues);
|
||||
$this->DisplayStatusTab($oPage);
|
||||
}
|
||||
@@ -208,7 +215,7 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
$oPage->add('<table class="synoptics"><tr><td style="color:#333;vertical-align:top">');
|
||||
|
||||
// List all the log entries for the user to select
|
||||
$oPage->add('<h2>'.Dict::S('Core:Synchro:History').'</h2>');
|
||||
$oPage->add('<h2 style="line-height:55px;">'.Dict::S('Core:Synchro:History').'</h2>');
|
||||
$oSetSynchroLog->Rewind();
|
||||
$oPage->add('<select size="25" onChange="UpdateSynoptics(this.value);">');
|
||||
$sSelected = ' selected'; // First log is selected by default
|
||||
@@ -362,6 +369,43 @@ EOF
|
||||
return $aData;
|
||||
}
|
||||
|
||||
public function GetIcon($bImgTag = true, $sMoreStyles = '')
|
||||
{
|
||||
if ($this->Get('url_icon') == '') return MetaModel::GetClassIcon(get_class($this), $bImgTag);
|
||||
if ($bImgTag)
|
||||
{
|
||||
return "<img src=\"".$this->Get('url_icon')."\" style=\"vertical-align:middle;$sMoreStyles\"/>";
|
||||
|
||||
}
|
||||
return $this->Get('url_icon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actual hyperlink to the remote application for the given replica and dest object
|
||||
*/
|
||||
public function GetApplicationUrl(DBObject $oDestObj, SynchroReplica $oReplica)
|
||||
{
|
||||
if ($this->Get('url_application') == '') return '';
|
||||
$aSearches = array();
|
||||
$aReplacements = array();
|
||||
foreach(MetaModel::ListAttributeDefs($this->GetTargetClass()) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsScalar())
|
||||
{
|
||||
$aSearches[] = '$this->'.$sAttCode.'$';
|
||||
$aReplacements[] = $oDestObj->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
$aData = $oReplica->LoadExtendedDataFromTable($this->GetDataTable());
|
||||
|
||||
foreach($aData as $sColumn => $value)
|
||||
{
|
||||
$aSearches[] = '$replica->'.$sColumn.'$';
|
||||
$aReplacements[] = $value;
|
||||
}
|
||||
return str_replace($aSearches, $aReplacements, $this->Get('url_application'));
|
||||
}
|
||||
|
||||
public function GetAttributeFlags($sAttCode)
|
||||
{
|
||||
if (($sAttCode == 'scope_class') && (!$this->IsNew()))
|
||||
@@ -1643,10 +1687,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$oSource = MetaModel::GetObject('SynchroDataSource', $this->Get('sync_source_id'));
|
||||
|
||||
$sSQLTable = $oSource->GetDataTable();
|
||||
$sSQL = "SELECT * FROM $sSQLTable WHERE id=".$this->GetKey();
|
||||
|
||||
$rQuery = CMDBSource::Query($sSQL);
|
||||
$aData = CMDBSource::FetchArray($rQuery);
|
||||
$aData = $this->LoadExtendedDataFromTable($sSQLTable);
|
||||
|
||||
$aHeaders = array('attcode' => array('label' => 'Attribute Code', 'description' => ''),
|
||||
'data' => array('label' => 'Value', 'description' => ''));
|
||||
@@ -1660,6 +1701,14 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$oPage->add('</td></tr></table>');
|
||||
|
||||
}
|
||||
|
||||
public function LoadExtendedDataFromTable($sSQLTable)
|
||||
{
|
||||
$sSQL = "SELECT * FROM $sSQLTable WHERE id=".$this->GetKey();
|
||||
|
||||
$rQuery = CMDBSource::Query($sSQL);
|
||||
return CMDBSource::FetchArray($rQuery);
|
||||
}
|
||||
}
|
||||
|
||||
// TO DO: finalize.... admins only ? which options ? troubleshoot WebPageMenuNode::__construct(.... sEnableClass...) ?
|
||||
|
||||
Reference in New Issue
Block a user