Explorar el Código

Synchro Data Sources Implementation on going...

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@1107 a333f486-631f-4898-b8df-5754b55c2be0
dflaven hace 14 años
padre
commit
4fbef2beda

+ 86 - 4
application/cmdbabstract.class.inc.php

@@ -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"')."&nbsp;$sLink</p>";
+			}
+			$sSynchroIcon = '&nbsp;<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()."&nbsp;\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 = "&nbsp;<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 = "&nbsp;<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;
 										}

+ 1 - 0
application/itopwebpage.class.inc.php

@@ -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

+ 48 - 1
core/dbobject.class.php

@@ -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


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 15 - 0
js/jquery.qtip-1.0.min.js


+ 55 - 6
synchro/synchrodatasource.class.inc.php

@@ -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...) ?

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio