diff --git a/core/dbobject.class.php b/core/dbobject.class.php index c9091119d..d50a55730 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -353,6 +353,12 @@ abstract class DBObject $this->RegisterAsDirty(); } + public function GetLabel($sAttCode) + { + $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); + return $oAttDef->GetLabel(); + } + public function Get($sAttCode) { if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this)))) diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index d14e363b5..daf2ef0f5 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -666,6 +666,50 @@ EOF // TO DO - check that triggers get dropped with the table } + protected function SendNotification($sSubject, $sBody) + { + $iContact = $this->Get('notify_contact_id'); + if ($iContact == 0) + { + // Leave silently... + return; + } + $oContact = MetaModel::GetObject('Contact', $iContact); + + // Determine the email attribute (the first one will be our choice) + $sEmailAttCode = null; + foreach (MetaModel::ListAttributeDefs(get_class($oContact)) as $sAttCode => $oAttDef) + { + if ($oAttDef instanceof AttributeEmailAddress) + { + $sEmailAttCode = $sAttCode; + // we've got one, exit the loop + break; + } + } + if (is_null($sEmailAttCode)) + { + // Leave silently... + return; + } + + $sTo = $oContact->Get($sEmailAttCode); + $sFrom = $sTo; + $sBody = '
Data synchronization: '.$this->GetHyperlink().'
'.$sBody; + + $sSubject = 'iTop Data Sync - '.$this->GetName().' - '.$sSubject; + + $oEmail = new Email(); + $oEmail->SetRecipientTO($sTo); + $oEmail->SetRecipientFrom($sFrom); + $oEmail->SetSubject($sSubject); + $oEmail->SetBody($sBody); + if ($oEmail->Send($aIssues) == EMAIL_SEND_ERROR) + { + // mmmm, what can I do? + } + } + /** * Perform a synchronization between the data stored in the replicas (&synchro_data_xxx_xx table) * and the iTop objects. If the lastFullLoadStartDate is NOT specified then the full_load_periodicity @@ -715,10 +759,44 @@ EOF try { $this->DoSynchronize($oLastFullLoadStartDate, $oMyChange, $oStatLog); - $oStatLog->Set('end_date', time()); $oStatLog->Set('status', 'completed'); $oStatLog->DBUpdateTracked($oMyChange); + + $iErrors = $oStatLog->GetErrorCount(); + if ($iErrors > 0) + { + $sIssuesOQL = "SELECT SynchroReplica WHERE sync_source_id=".$this->GetKey()." AND status_last_error!=''"; + $sAbsoluteUrl = utils::GetAbsoluteUrlPath(); + $sIssuesURL = "$sAbsoluteUrl../synchro/replica.php?operation=oql&datasource=".$this->GetKey()."&oql=".urlencode($sIssuesOQL); + $sSeeIssues = ""; + + $sStatistics = "The synchronization has been executed, $iErrors errors have been encountered. Click here to see the records being currently in error.
".$sStatistics); + } + else + { + //$this->SendNotification('success', 'The synchronization has been successfully executed.
'); + } } catch (SynchroExceptionNotStarted $e) { @@ -727,6 +805,7 @@ EOF $oStatLog->Set('status', 'error'); $oStatLog->Set('last_error', $e->getMessage()); $oStatLog->DBDeleteTracked($oMyChange); + $this->SendNotification('fatal error', 'The synchronization could not start: \''.$e->getMessage().'\'
Please check its configuration
'); } catch (Exception $e) { @@ -734,8 +813,10 @@ EOF $oStatLog->Set('status', 'error'); $oStatLog->Set('last_error', $e->getMessage()); $oStatLog->DBUpdateTracked($oMyChange); + $this->SendNotification('exception', 'The synchronization has been interrupted: \''.$e->getMessage().'\'
Please contact the application support team
'); } self::$m_oCurrentTask = null; + return $oStatLog; } @@ -885,7 +966,8 @@ EOF while($oReplica = $oSetToSync->Fetch()) { - $oReplica->Synchro($this, $aReconciliationKeys, $aAttributes, $oMyChange, $oStatLog); + $oReplica->Synchro($this, $aReconciliationKeys, $aAttributes, $oMyChange, $oStatLog); + $oReplica->DBUpdateTracked($oMyChange); } // Get all the replicas that are to be deleted @@ -1169,6 +1251,18 @@ class SynchroLog extends DBObject // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form } + /** + * Helper + */ + function GetErrorCount() + { + return $this->Get('stats_nb_obj_deleted_errors') + + $this->Get('stats_nb_obj_obsoleted_errors') + + $this->Get('stats_nb_obj_created_errors') + + $this->Get('stats_nb_obj_updated_errors') + + $this->Get('stats_nb_replica_reconciled_errors'); + } + /** * Increments a statistics counter */ @@ -1367,8 +1461,8 @@ class SynchroReplica extends DBObject implements iDisplay else { // Reconciliation could not be performed - log and EXIT - $oStatLog->AddTrace("Could not reconcile on null value: ".$sFilterCode, $this); - $this->SetLastError('Could not reconcile on null value: '.$sFilterCode); + $oStatLog->AddTrace("Could not reconcile on null value for attribute '$sFilterCode'", $this); + $this->SetLastError("Could not reconcile on null value for attribute '$sFilterCode'"); $oStatLog->Inc('stats_nb_replica_reconciled_errors'); return; } @@ -1455,7 +1549,6 @@ class SynchroReplica extends DBObject implements iDisplay default: // Do nothing in all other cases } - $this->DBUpdateTracked($oChange); } /**