diff --git a/core/dbobject.class.php b/core/dbobject.class.php
index 5b1e3dd18..854390796 100644
--- a/core/dbobject.class.php
+++ b/core/dbobject.class.php
@@ -57,7 +57,7 @@ require_once('mutex.class.inc.php');
/**
- * A persistent object, as defined by the metamodel
+ * A persistent object, as defined by the metamodel
*
* @package iTopORM
* @api
@@ -299,9 +299,9 @@ abstract class DBObject implements iDisplay
/**
* Whether the object is already persisted in DB or not.
- *
+ *
* @api
- *
+ *
* @return bool
*/
public function IsNew()
@@ -311,9 +311,9 @@ abstract class DBObject implements iDisplay
/**
* Returns an Id for memory objects
- *
+ *
* @internal
- *
+ *
* @param string $sClass
*
* @return int
@@ -350,7 +350,7 @@ abstract class DBObject implements iDisplay
$sRet .= "$sClass::$iPKey ($sFriendlyname)
\n";
return $sRet;
}
-
+
/**
* Alias of DBObject::Reload()
*
@@ -373,7 +373,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see m_bFullyLoaded
- *
+ *
* @return bool
* @throws CoreException
*/
@@ -496,7 +496,7 @@ abstract class DBObject implements iDisplay
{
$aAttList = $aAttToLoad[$sClassAlias];
}
-
+
foreach($aAttList as $sAttCode=>$oAttDef)
{
// Skip links (could not be loaded by the mean of this query)
@@ -556,7 +556,7 @@ abstract class DBObject implements iDisplay
$bFullyLoaded = false;
}
}
-
+
// Load extended data
if ($aExtendedDataSpec != null)
{
@@ -580,7 +580,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see Set()
- *
+ *
* @param string $sAttCode
* @param mixed $value
*/
@@ -785,11 +785,11 @@ abstract class DBObject implements iDisplay
/**
* Get the label of an attribute.
- *
+ *
* Shortcut to the field's AttributeDefinition->GetLabel()
*
* @api
- *
+ *
* @param string $sAttCode
*
* @return string
@@ -862,7 +862,7 @@ abstract class DBObject implements iDisplay
*
* @internal
* @see Get
- *
+ *
* @param string $sAttCode
*
* @return int|mixed|null
@@ -967,7 +967,7 @@ abstract class DBObject implements iDisplay
* Returns the default value of the $sAttCode.
*
* Returns the default value of the given attribute.
- *
+ *
* @internal
*
* @param string $sAttCode
@@ -988,12 +988,12 @@ abstract class DBObject implements iDisplay
* @internal
*
* @return array|null
- */
+ */
public function GetExtendedData()
{
return $this->m_aExtendedData;
}
-
+
/**
* Set the HighlightCode
*
@@ -1015,7 +1015,7 @@ abstract class DBObject implements iDisplay
{
$fCurrentRank = $aHighlightScale[$this->m_sHighlightCode]['rank'];
}
-
+
if (array_key_exists($sCode, $aHighlightScale))
{
$fRank = $aHighlightScale[$sCode]['rank'];
@@ -1025,13 +1025,13 @@ abstract class DBObject implements iDisplay
}
}
}
-
+
/**
* Get the current HighlightCode
- *
+ *
* @internal
* @used-by DBObject::ComputeHighlightCode()
- *
+ *
* @return string|null The Hightlight code (null if none set, meaning rank = 0)
*/
protected function GetHighlightCode()
@@ -1080,7 +1080,7 @@ abstract class DBObject implements iDisplay
* corresponding to the external key and getting the value from it
*
* UNUSED ?
- *
+ *
* @internal
* @todo: check if this is dead code.
*
@@ -1149,7 +1149,7 @@ abstract class DBObject implements iDisplay
/**
* @api
- *
+ *
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1195,11 +1195,11 @@ abstract class DBObject implements iDisplay
/**
* Get the value as it must be in the edit areas (forms)
- *
+ *
* Makes a raw text representation of the value.
*
* @internal
- *
+ *
* @param string $sAttCode
*
* @return int|mixed|string
@@ -1229,7 +1229,7 @@ abstract class DBObject implements iDisplay
else
{
$sEditValue = 0;
- }
+ }
}
else
{
@@ -1245,14 +1245,14 @@ abstract class DBObject implements iDisplay
/**
* Get $sAttCode formatted as XML
- *
+ *
* The returned value is a text that is suitable for insertion into an XML node.
* Depending on the type of attribute, the returned text is either:
* * A literal, with XML entities already escaped,
* * XML
*
* @api
- *
+ *
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1290,10 +1290,10 @@ abstract class DBObject implements iDisplay
}
/**
- *
+ *
* @see GetAsHTML()
* @see GetOriginal()
- *
+ *
* @param string $sAttCode
* @param bool $bLocalize
*
@@ -1468,7 +1468,7 @@ abstract class DBObject implements iDisplay
/**
* @internal
- *
+ *
* @param string $sClass
*
* @return mixed
@@ -1523,7 +1523,7 @@ abstract class DBObject implements iDisplay
* Get the id
*
* @api
- *
+ *
* @return string|null
*/
public function GetKey()
@@ -1534,7 +1534,7 @@ abstract class DBObject implements iDisplay
/**
* Primary key Setter
* Usable only for not yet persisted DBObjects
- *
+ *
* @internal
*
* @param int $iNewKey the desired identifier
@@ -1547,7 +1547,7 @@ abstract class DBObject implements iDisplay
{
throw new CoreException("An object id must be an integer value ($iNewKey)");
}
-
+
if ($this->m_bIsInDB && !empty($this->m_iKey) && ($this->m_iKey != $iNewKey))
{
throw new CoreException("Changing the key ({$this->m_iKey} to $iNewKey) on an object (class {".get_class($this).") wich already exists in the Database");
@@ -1557,7 +1557,7 @@ abstract class DBObject implements iDisplay
/**
* Get the icon representing this object
- *
+ *
* @api
*
* @param boolean $bImgTag If true the result is a full IMG tag (or an empty string if no icon is defined)
@@ -1647,7 +1647,7 @@ abstract class DBObject implements iDisplay
*
* Returns the label as defined in the dictionary for the language of the current user
*
- * @api
+ * @api
*
* @return string (empty for default name scheme)
*/
@@ -1714,7 +1714,7 @@ abstract class DBObject implements iDisplay
/**
* Helper to get the state
- *
+ *
* @api
*
* @return mixed|string '' if no state attribute, object representing its value otherwise
@@ -1736,9 +1736,9 @@ abstract class DBObject implements iDisplay
/**
* Get the label (raw text) of the current state
* helper for MetaModel::GetStateLabel()
- *
+ *
* @api
- *
+ *
* @return mixed|string
*
* @throws ArchivedObjectException
@@ -1785,7 +1785,7 @@ abstract class DBObject implements iDisplay
* Define attributes read-only from the end-user perspective
*
* @return array|null List of attcodes
- */
+ */
public static function GetReadOnlyAttributes()
{
return null;
@@ -1794,14 +1794,14 @@ abstract class DBObject implements iDisplay
/**
* Get predefined objects
- *
+ *
* The predefined objects will be synchronized with the DB at each install/upgrade
* As soon as a class has predefined objects, then nobody can create nor delete objects
*
* @internal
*
* @return array An array of id => array of attcode => php value(so-called "real value": integer, string, ormDocument, DBObjectSet, etc.)
- */
+ */
public static function GetPredefinedObjects()
{
return null;
@@ -1930,7 +1930,7 @@ abstract class DBObject implements iDisplay
* Note: Attributes (and flags) from the target state and the transition are combined.
*
* @internal
- *
+ *
* @param string $sStimulus
* @param string $sOriginState Default is current state
*
@@ -2137,7 +2137,7 @@ abstract class DBObject implements iDisplay
/**
* @internal
- *
+ *
* @throws \CoreException
* @throws \OQLException
*
@@ -2509,7 +2509,7 @@ abstract class DBObject implements iDisplay
*
* an array of displayable error is added in {@see DBObject::$m_aDeleteIssues}
*
- * @internal
+ * @internal
*
* @param \DeletionPlan $oDeletionPlan
*
@@ -2626,7 +2626,7 @@ abstract class DBObject implements iDisplay
{
// The value is a scalar, the comparison must be 100% strict
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
- {
+ {
//echo "$sAtt:
\n";
//var_dump($this->m_aOrigValues[$sAtt]);
//var_dump($proposedValue);
@@ -2748,7 +2748,7 @@ abstract class DBObject implements iDisplay
/**
* Used only by insert, Meant to be overloaded
- *
+ *
* @overwritable-hook You can extend this method in order to provide your own logic.
*/
protected function OnObjectKeyReady()
@@ -2856,7 +2856,7 @@ abstract class DBObject implements iDisplay
// fields in first array, values in the second
$aFieldsToWrite = array();
$aValuesToWrite = array();
-
+
if (!empty($this->m_iKey) && ($this->m_iKey >= 0))
{
// Add it to the list of fields to write
@@ -2865,7 +2865,7 @@ abstract class DBObject implements iDisplay
}
$aHierarchicalKeys = array();
-
+
foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef) {
// Skip this attribute if not defined in this table
if ((!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode) && !$oAttDef->CopyOnAllTables())
@@ -2875,7 +2875,7 @@ abstract class DBObject implements iDisplay
$aAttColumns = $oAttDef->GetSQLValues($this->m_aCurrValues[$sAttCode]);
foreach($aAttColumns as $sColumn => $sValue)
{
- $aFieldsToWrite[] = "`$sColumn`";
+ $aFieldsToWrite[] = "`$sColumn`";
$aValuesToWrite[] = CMDBSource::Quote($sValue);
}
if ($oAttDef->IsHierarchicalKey())
@@ -2899,7 +2899,7 @@ abstract class DBObject implements iDisplay
self::$m_aBulkInsertCols[$sClass][$sTable] = implode(', ', $aFieldsToWrite);
}
self::$m_aBulkInsertItems[$sClass][$sTable][] = '('.implode (', ', $aValuesToWrite).')';
-
+
$iNewKey = 999999; // TODO - compute next id....
}
else
@@ -2984,7 +2984,7 @@ abstract class DBObject implements iDisplay
// fields in first array, values in the second
$aFieldsToWrite = array();
$aValuesToWrite = array();
-
+
if (!empty($this->m_iKey) && ($this->m_iKey >= 0))
{
// Add it to the list of fields to write
@@ -3019,7 +3019,7 @@ abstract class DBObject implements iDisplay
$aAttColumns = $oAttDef->GetSQLValues($value);
foreach($aAttColumns as $sColumn => $sValue)
{
- $aFieldsToWrite[] = "`$sColumn`";
+ $aFieldsToWrite[] = "`$sColumn`";
$aValuesToWrite[] = CMDBSource::Quote($sValue);
}
if ($oAttDef->IsHierarchicalKey())
@@ -3157,6 +3157,10 @@ abstract class DBObject implements iDisplay
// First query built upon on the root class, because the ID must be created first
$this->m_iKey = $this->DBInsertSingleTable($sRootClass);
+ //since N°5324: issue with test and db links events
+ $this->SetReadOnly('No modification allowed during transaction');
+ MetaModel::StartReentranceProtection($this);
+
// Then do the leaf class, if different from the root class
if ($sClass != $sRootClass) {
$this->DBInsertSingleTable($sClass);
@@ -3206,6 +3210,7 @@ abstract class DBObject implements iDisplay
}
}
+ $this->SetReadWrite();
$this->m_bIsInDB = true;
$this->m_bDirty = false;
foreach ($this->m_aCurrValues as $sAttCode => $value) {
@@ -3215,9 +3220,6 @@ abstract class DBObject implements iDisplay
$this->m_aOrigValues[$sAttCode] = $value;
}
- // Prevent DBUpdate at this point (reentrance protection)
- MetaModel::StartReentranceProtection($this);
-
try {
$this->PostInsertActions();
}
@@ -3293,7 +3295,7 @@ abstract class DBObject implements iDisplay
$this->RecordObjCreation();
return $ret;
}
-
+
/**
* This function is automatically called after cloning an object with the "clone" PHP language construct
* The purpose of this method is to reset the appropriate attributes of the object in
@@ -3382,6 +3384,7 @@ abstract class DBObject implements iDisplay
}
}
+ $this->SetReadOnly('No modification allowed during transaction');
$iTransactionRetry = 1;
$bIsTransactionEnabled = MetaModel::GetConfig()->Get('db_core_transactions_enabled');
if ($bIsTransactionEnabled) {
@@ -3496,6 +3499,8 @@ abstract class DBObject implements iDisplay
// following lines are resetting changes (so after this {@see DBObject::ListChanges()} won't return changes anymore)
// new values are already in the object (call {@see DBObject::Get()} to get them)
// call {@see DBObject::ListPreviousValuesForUpdatedAttributes()} to get changed fields and previous values
+
+ $this->SetReadWrite();
$this->m_bDirty = false;
$this->m_aTouchedAtt = array();
$this->m_aModifiedAtt = array();
@@ -3909,7 +3914,7 @@ abstract class DBObject implements iDisplay
* First, checks if the object can be deleted regarding database integrity.
* If the answer is yes, it performs any required cleanup (delete other objects or reset external keys) in addition to the object
* deletion.
- *
+ *
* @api
*
* @param \DeletionPlan $oDeletionPlan Do not use: aims at dealing with recursion
@@ -4332,7 +4337,7 @@ abstract class DBObject implements iDisplay
*
* @api
*
- */
+ */
public function Reset($sAttCode)
{
$this->Set($sAttCode, $this->GetDefaultValue($sAttCode));
@@ -4344,7 +4349,7 @@ abstract class DBObject implements iDisplay
* Suitable for use as a lifecycle action
*
* @api
- */
+ */
public function Copy($sDestAttCode, $sSourceAttCode)
{
$oTypeValueToCopy = MetaModel::GetAttributeDef(get_class($this), $sSourceAttCode);
@@ -4674,7 +4679,7 @@ abstract class DBObject implements iDisplay
{
throw new CoreException("Unknown attribute '$sExtKeyAttCode' for the class ".get_class($this));
}
-
+
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
if (!$oKeyAttDef instanceof AttributeExternalKey)
{
@@ -4692,14 +4697,14 @@ abstract class DBObject implements iDisplay
$ret = $oRemoteObj->GetForTemplate($sRemoteAttCode);
}
}
- else
+ else
{
switch($sPlaceholderAttCode)
{
case 'id':
$ret = $this->GetKey();
break;
-
+
case 'name()':
$ret = $this->GetName();
break;
@@ -4886,7 +4891,7 @@ abstract class DBObject implements iDisplay
if ($oOwner)
{
$sLinkSetOwnerClass = get_class($oOwner);
-
+
$oMyChangeOp = MetaModel::NewObject($sChangeOpClass);
$oMyChangeOp->Set("objclass", $sLinkSetOwnerClass);
$oMyChangeOp->Set("objkey", $iLinkSetOwnerId);
@@ -4913,7 +4918,7 @@ abstract class DBObject implements iDisplay
{
/** @var \AttributeLinkedSet $oLinkSet */
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_LIST) == 0) continue;
-
+
$iLinkSetOwnerId = $this->Get($sExtKeyAttCode);
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, 'CMDBChangeOpSetAttributeLinksAddRemove');
if ($oMyChangeOp)
@@ -4983,7 +4988,7 @@ abstract class DBObject implements iDisplay
// Keep track of link changes
//
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_DETAILS) == 0) continue;
-
+
$iLinkSetOwnerId = $this->Get($sExtKeyAttCode);
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, 'CMDBChangeOpSetAttributeLinksTune');
if ($oMyChangeOp)
@@ -5132,7 +5137,7 @@ abstract class DBObject implements iDisplay
$this->FireEventCheckToDelete($oDeletionPlan);
$this->DoCheckToDelete($oDeletionPlan);
$oDeletionPlan->SetDeletionIssues($this, $this->m_aDeleteIssues, $this->m_bSecurityIssue);
-
+
$aDependentObjects = $this->GetReferencingObjects(true /* allow all data */);
// Getting and setting time limit are not symmetric:
@@ -5314,7 +5319,7 @@ abstract class DBObject implements iDisplay
$aSynchroClasses[] = $sTarget;
}
}
-
+
foreach($aSynchroClasses as $sClass)
{
if ($this instanceof $sClass)
diff --git a/core/metamodel.class.php b/core/metamodel.class.php
index 7e3b8cdc8..eef5783aa 100644
--- a/core/metamodel.class.php
+++ b/core/metamodel.class.php
@@ -1241,7 +1241,7 @@ abstract class MetaModel
}
$sTable = self::DBGetTable($sClass);
- // Could be completed later with all the classes that are using a given table
+ // Could be completed later with all the classes that are using a given table
if (!array_key_exists($sTable, $aTables)) {
$aTables[$sTable] = array();
}
@@ -3522,7 +3522,7 @@ abstract class MetaModel
}
// Set the "host class" as soon as possible, since HierarchicalKeys use it for their 'target class' as well
- // and this needs to be know early (for Init_IsKnowClass 19 lines below)
+ // and this needs to be know early (for Init_IsKnowClass 19 lines below)
$oAtt->SetHostClass($sTargetClass);
// Some attributes could refer to a class
@@ -3564,7 +3564,7 @@ abstract class MetaModel
self::$m_aAttribDefs[$sTargetClass][$oAtt->GetCode()] = $oAtt;
self::$m_aAttribOrigins[$sTargetClass][$oAtt->GetCode()] = $sTargetClass;
- // Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
+ // Note: it looks redundant to put targetclass there, but a mix occurs when inheritance is used
}
/**
@@ -3764,7 +3764,7 @@ abstract class MetaModel
self::$m_aStimuli[$sTargetClass][$oStimulus->GetCode()] = $oStimulus;
// I wanted to simplify the syntax of the declaration of objects in the biz model
- // Therefore, the reference to the host class is set there
+ // Therefore, the reference to the host class is set there
$oStimulus->SetHostClass($sTargetClass);
}
@@ -6470,7 +6470,7 @@ abstract class MetaModel
$aCache['m_aExtensionClassNames'] = self::$m_aExtensionClassNames;
$aCache['m_Category2Class'] = self::$m_Category2Class;
$aCache['m_aRootClasses'] = self::$m_aRootClasses; // array of "classname" => "rootclass"
- $aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
+ $aCache['m_aParentClasses'] = self::$m_aParentClasses; // array of ("classname" => array of "parentclass")
$aCache['m_aChildClasses'] = self::$m_aChildClasses; // array of ("classname" => array of "childclass")
$aCache['m_aClassParams'] = self::$m_aClassParams; // array of ("classname" => array of class information)
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
@@ -7567,6 +7567,20 @@ abstract class MetaModel
return false;
}
+ /**
+ * @since 3.1.0 N°5324: to ease reentrance checks when using events on links (to avoid reentering if main link object ongoing operation)
+ */
+ public static function GetReentranceObjectByChildClass(string $sParentClass, $sKey)
+ {
+ foreach (self::EnumChildClasses($sParentClass, ENUM_CHILD_CLASSES_ALL, false) as $sChildClass){
+ if (self::GetReentranceObject($sChildClass, $sKey)){
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* @param \DBObject $oObject
*
diff --git a/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php b/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php
index 1da291fdc..c4ab5088b 100644
--- a/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php
+++ b/datamodels/2.x/itop-profiles-itil/src/UserProfilesEventListener.php
@@ -41,19 +41,27 @@ class UserProfilesEventListener implements iEventServiceSetup
return;
}
- $callback = [$this, 'OnUserProfileLinkChange'];
$aEventSource = [\User::class, \UserExternal::class, \UserInternal::class];
-
EventService::RegisterListener(
EVENT_DB_BEFORE_WRITE,
- $callback,
+ [$this, 'OnUserEdition'],
$aEventSource
);
EventService::RegisterListener(
- EVENT_DB_LINKS_CHANGED,
- $callback,
- $aEventSource
+ EVENT_DB_BEFORE_WRITE,
+ [ $this, 'OnUserProfileEdition' ],
+ [ \URP_UserProfile::class ],
+ [],
+ null
+ );
+
+ EventService::RegisterListener(
+ EVENT_DB_CHECK_TO_DELETE,
+ [ $this, 'OnUserProfileLinkDeletion' ],
+ [ \URP_UserProfile::class ],
+ [],
+ null
);
}
@@ -62,12 +70,13 @@ class UserProfilesEventListener implements iEventServiceSetup
return $this->bIsRepairmentEnabled;
}
- public function OnUserProfileLinkChange(EventData $oEventData): void {
+
+ public function OnUserEdition(EventData $oEventData): void {
/** @var \User $oObject */
$oUser = $oEventData->Get('object');
try {
- $this->RepairProfiles($oUser);
+ $this->ValidateThenRepairOrWarn($oUser);
} catch (Exception $e) {
IssueLog::Error('Exception occurred on RepairProfiles', LogChannels::DM_CRUD, [
'user_class' => get_class($oUser),
@@ -75,9 +84,119 @@ class UserProfilesEventListener implements iEventServiceSetup
'exception_message' => $e->getMessage(),
'exception_stacktrace' => $e->getTraceAsString(),
]);
+ if ($e instanceof \CoreCannotSaveObjectException){
+ throw $e;
+ }
}
}
+ public function OnUserProfileEdition(EventData $oEventData): void {
+ $oURP_UserProfile = $oEventData->Get('object');
+
+ try {
+ $iUserId = $oURP_UserProfile->Get('userid');
+ $oUser = \MetaModel::GetReentranceObjectByChildClass(\User::class, $iUserId);
+ if (false !== $oUser){
+ //user edition: handled by other event
+ return;
+ }
+
+ $oUser = \MetaModel::GetObject(\User::class, $iUserId);
+ $aChanges = $oURP_UserProfile->ListChanges();
+ if (array_key_exists('userid', $aChanges)) {
+ $iUserId = $oURP_UserProfile->GetOriginal('userid');
+ $oPreviousUser = \MetaModel::GetObject(\User::class, $iUserId);
+
+ $oProfileLinkSet = $oPreviousUser->Get('profile_list');
+ $oProfileLinkSet->Rewind();
+ $iCount = 0;
+ while ($oCurrentURP_UserProfile = $oProfileLinkSet->Fetch()) {
+ if ($oCurrentURP_UserProfile->Get('userid') !== $oCurrentURP_UserProfile->GetOriginal('userid')) {
+ $sRemovedProfileId = $oCurrentURP_UserProfile->GetOriginal('profileid');
+ continue;
+ }
+
+ $iCount++;
+ if ($iCount > 1){
+ //more than one profile: no repairment needed
+ return;
+ }
+ $sSingleProfileName = $oCurrentURP_UserProfile->Get('profile');
+ }
+ $this->RepairProfileChangesOrWarn($oPreviousUser, $sSingleProfileName, $oURP_UserProfile, $sRemovedProfileId);
+ } else if (array_key_exists('profileid', $aChanges)){
+ $oCurrentUserProfileSet = $oUser->Get('profile_list');
+ if ($oCurrentUserProfileSet->Count() === 1){
+ $oProfile = $oCurrentUserProfileSet->Fetch();
+
+ $this->RepairProfileChangesOrWarn($oUser, $oProfile->Get('profile'), $oURP_UserProfile, $oProfile->GetOriginal("profileid"));
+ }
+ }
+ } catch (Exception $e) {
+ IssueLog::Error('OnUserProfileEdition Exception', LogChannels::DM_CRUD, [
+ 'user_id' => $iUserId,
+ 'lnk_id' => $oURP_UserProfile->GetKey(),
+ 'exception_message' => $e->getMessage(),
+ 'exception_stacktrace' => $e->getTraceAsString(),
+ ]);
+ if ($e instanceof \CoreCannotSaveObjectException){
+ throw $e;
+ }
+ }
+ }
+
+ public function OnUserProfileLinkDeletion(EventData $oEventData): void {
+ $oURP_UserProfile = $oEventData->Get('object');
+
+ try {
+ $iUserId = $oURP_UserProfile->Get('userid');
+ $oUser = \MetaModel::GetReentranceObjectByChildClass(\User::class, $iUserId);
+ if (false !== $oUser){
+ //user edition: handled by other event
+ return;
+ }
+
+ $oUser = \MetaModel::GetObject(\User::class, $iUserId);
+
+ /** @var \DeletionPlan $oDeletionPlan */
+ $oDeletionPlan = $oEventData->Get('deletion_plan');
+ $aDeletedURP_UserProfiles = [];
+ if (! is_null($oDeletionPlan)){
+ $aListDeletes = $oDeletionPlan->ListDeletes();
+ if (array_key_exists(\URP_UserProfile::class, $aListDeletes)) {
+ foreach ($aListDeletes[\URP_UserProfile::class] as $iId => $aDeletes) {
+ $aDeletedURP_UserProfiles []= $iId;
+ }
+ }
+ }
+
+ $oProfileLinkSet = $oUser->Get('profile_list');
+ $oProfileLinkSet->Rewind();
+ $iCount = 0;
+ while ($oCurrentURP_UserProfile = $oProfileLinkSet->Fetch()) {
+ if (in_array($oCurrentURP_UserProfile->GetKey(), $aDeletedURP_UserProfiles)) {
+ continue;
+ }
+ $iCount++;
+ if ($iCount > 1){
+ //more than one profile: no repairment needed
+ return;
+ }
+ $sSingleProfileName = $oCurrentURP_UserProfile->Get('profile');
+ }
+
+ $this->RepairProfileChangesOrWarn($oUser, $sSingleProfileName, $oURP_UserProfile, $oURP_UserProfile->Get('profileid'), true);
+ } catch (Exception $e) {
+ IssueLog::Error('OnUserProfileLinkDeletion Exception', LogChannels::DM_CRUD, [
+ 'user_id' => $iUserId,
+ 'profile_id' => $oURP_UserProfile->Get('profileid'),
+ 'exception_message' => $e->getMessage(),
+ 'exception_stacktrace' => $e->getTraceAsString(),
+ ]);
+ }
+ }
+
+
/**
* @param $aPortalDispatcherData: passed only for testing purpose
*
@@ -125,83 +244,113 @@ class UserProfilesEventListener implements iEventServiceSetup
return;
}
+
+ $this->FetchRepairingProfileIds($aNonStandaloneProfiles);
+ }
+
+ public function FetchRepairingProfileIds(array $aNonStandaloneProfiles) : void {
+ $aProfiles = [];
try {
- $this->FetchRepairingProfileIds($aNonStandaloneProfiles);
+ $aProfilesToSearch = array_unique(array_values($aNonStandaloneProfiles));
+ if(($iIndex = array_search(null, $aProfilesToSearch)) !== false) {
+ unset($aProfilesToSearch[$iIndex]);
+ }
+
+ if (1 === count($aProfilesToSearch)){
+ $sInCondition = sprintf('"%s"', array_pop($aProfilesToSearch));
+ } else {
+ $sInCondition = sprintf('"%s"', implode('","', $aProfilesToSearch));
+ }
+
+ $sOql = "SELECT URP_Profiles WHERE name IN ($sInCondition)";
+ $oSearch = \DBSearch::FromOQL($sOql);
+ $oSearch->AllowAllData();
+ $oSet = new \DBObjectSet($oSearch);
+ while(($oProfile = $oSet->Fetch()) != null) {
+ $sProfileName = $oProfile->Get('name');
+ $aProfiles[$sProfileName] = $oProfile->GetKey();
+ }
+
+ $this->aNonStandaloneProfilesMap = [];
+ foreach ($aNonStandaloneProfiles as $sNonStandaloneProfileName => $sRepairProfileName) {
+ if (is_null($sRepairProfileName)) {
+ $this->aNonStandaloneProfilesMap[$sNonStandaloneProfileName] = null;
+ continue;
+ }
+
+ if (! array_key_exists($sRepairProfileName, $aProfiles)) {
+ throw new \Exception(sprintf("%s is badly configured. profile $sRepairProfileName does not exist.", self::USERPROFILE_REPAIR_ITOP_PARAM_NAME));
+ }
+
+ $this->aNonStandaloneProfilesMap[$sNonStandaloneProfileName] = $aProfiles[$sRepairProfileName];
+ }
+
+ $this->bIsRepairmentEnabled = true;
} catch (\Exception $e) {
IssueLog::Error('Exception when searching user portal profile', LogChannels::DM_CRUD, [
'exception_message' => $e->getMessage(),
'exception_stacktrace' => $e->getTraceAsString(),
+ 'aProfiles' => $aProfiles,
+ 'aNonStandaloneProfiles' => $aNonStandaloneProfiles,
]);
$this->bIsRepairmentEnabled = false;
- return;
- }
-
- $this->bIsRepairmentEnabled = true;
- }
-
- public function FetchRepairingProfileIds(array $aNonStandaloneProfiles) : void {
- $aProfilesToSearch = array_unique(array_values($aNonStandaloneProfiles));
- if(($iIndex = array_search(null, $aProfilesToSearch)) !== false) {
- unset($aProfilesToSearch[$iIndex]);
- }
-
- if (1 === count($aProfilesToSearch)){
- $sInCondition = sprintf('"%s"', array_pop($aProfilesToSearch));
- } else {
- $sInCondition = sprintf('"%s"', implode('","', $aProfilesToSearch));
- }
-
- $sOql = "SELECT URP_Profiles WHERE name IN ($sInCondition)";
- $oSearch = \DBSearch::FromOQL($sOql);
- $oSearch->AllowAllData();
- $oSet = new \DBObjectSet($oSearch);
- $aProfiles = [];
- while(($oProfile = $oSet->Fetch()) != null) {
- $sProfileName = $oProfile->Get('name');
- $aProfiles[$sProfileName] = $oProfile->GetKey();
- }
-
- $this->aNonStandaloneProfilesMap = [];
- foreach ($aNonStandaloneProfiles as $sNonStandaloneProfileName => $sRepairProfileName) {
- if (is_null($sRepairProfileName)) {
- $this->aNonStandaloneProfilesMap[$sNonStandaloneProfileName] = null;
- continue;
- }
-
- if (!array_key_exists($sRepairProfileName, $aProfiles)) {
- throw new \Exception(sprintf("%s is badly configured. profile $sRepairProfileName does not exist.", self::USERPROFILE_REPAIR_ITOP_PARAM_NAME));
- }
-
- $this->aNonStandaloneProfilesMap[$sNonStandaloneProfileName] = $aProfiles[$sRepairProfileName];
}
}
- public function RepairProfiles(?\User $oUser) : void
+ public function ValidateThenRepairOrWarn(\User $oUser) : void
{
- if (!is_null($oUser))
- {
- $oCurrentUserProfileSet = $oUser->Get('profile_list');
- if ($oCurrentUserProfileSet->Count() === 1){
- $oProfile = $oCurrentUserProfileSet->Fetch();
- $sSingleProfileName = $oProfile->Get('profile');
+ $oCurrentUserProfileSet = $oUser->Get('profile_list');
+ if ($oCurrentUserProfileSet->Count() === 1){
+ $oProfile = $oCurrentUserProfileSet->Fetch();
- if (array_key_exists($sSingleProfileName, $this->aNonStandaloneProfilesMap)) {
- $sRepairingProfileId = $this->aNonStandaloneProfilesMap[$sSingleProfileName];
- if (is_null($sRepairingProfileId)){
- //Notify current user via session messages that there will be an issue
- //Without preventing from commiting
- $sMessage = \Dict::Format("Class:User/NonStandaloneProfileWarning", $sSingleProfileName);
- $oUser::SetSessionMessage(get_class($oUser), $oUser->GetKey(), 1, $sMessage, 'WARNING', 1);
- } else {
- //Completing profiles profiles by adding repairing one : by default portal user to a power portal user
- $oUserProfile = new \URP_UserProfile();
- $oUserProfile->Set('profileid', $sRepairingProfileId);
- $oCurrentUserProfileSet->AddItem($oUserProfile);
- $oUser->Set('profile_list', $oCurrentUserProfileSet);
- }
- }
+ $this->RepairUserChangesOrWarn($oUser, $oProfile->Get('profile'));
+ }
+ }
+
+ public function RepairUserChangesOrWarn(\User $oUser, string $sSingleProfileName) : void {
+ if (array_key_exists($sSingleProfileName, $this->aNonStandaloneProfilesMap)) {
+ $sRepairingProfileId = $this->aNonStandaloneProfilesMap[$sSingleProfileName];
+ if (is_null($sRepairingProfileId)){
+ //Notify current user via session messages that there will be an issue
+ //Without preventing from commiting
+ $sMessage = \Dict::Format("Class:User/NonStandaloneProfileWarning", $sSingleProfileName);
+ //$oUser::SetSessionMessage(get_class($oUser), $oUser->GetKey(), 1, $sMessage, 'WARNING', 1);
+ throw new \CoreCannotSaveObjectException(array('issues' => [$sMessage], 'class' => get_class($oUser), 'id' => $oUser->GetKey()));
+ } else {
+ //Completing profiles profiles by adding repairing one : by default portal user to a power portal user
+ $oUserProfile = new \URP_UserProfile();
+ $oUserProfile->Set('profileid', $sRepairingProfileId);
+ $oCurrentUserProfileSet = $oUser->Get('profile_list');
+ $oCurrentUserProfileSet->AddItem($oUserProfile);
+ $oUser->Set('profile_list', $oCurrentUserProfileSet);
}
}
}
+ public function RepairProfileChangesOrWarn(\User $oUser, string $sSingleProfileName, \URP_UserProfile $oURP_UserProfile, string $sRemovedProfileId, $bIsRemoval=false) : void {
+ if (array_key_exists($sSingleProfileName, $this->aNonStandaloneProfilesMap)) {
+ $sRepairingProfileId = $this->aNonStandaloneProfilesMap[$sSingleProfileName];
+ if (is_null($sRepairingProfileId)
+ || ($sRepairingProfileId === $sRemovedProfileId) //cannot repair by readding same remove profile as it will raise uniqueness rule
+ ){
+ //Notify current user via session messages that there will be an issue
+ //Without preventing from commiting
+ $sMessage = \Dict::Format("Class:User/NonStandaloneProfileWarning", $sSingleProfileName);
+ //$oURP_UserProfile::SetSessionMessage(get_class($oURP_UserProfile), $oURP_UserProfile->GetKey(), 1, $sMessage, 'WARNING', 1);
+ if ($bIsRemoval){
+ $oURP_UserProfile->AddDeleteIssue($sMessage);
+ } else {
+ throw new \CoreCannotSaveObjectException(array('issues' => [$sMessage], 'class' => get_class($oURP_UserProfile), 'id' => $oURP_UserProfile->GetKey()));
+ }
+ } else {
+ //Completing profiles profiles by adding repairing one : by default portal user to a power portal user
+ $oUserProfile = new \URP_UserProfile();
+ $oUserProfile->Set('profileid', $sRepairingProfileId);
+ $oCurrentUserProfileSet = $oUser->Get('profile_list');
+ $oCurrentUserProfileSet->AddItem($oUserProfile);
+ $oUser->Set('profile_list', $oCurrentUserProfileSet);
+ $oUser->DBWrite();
+ }
+ }
+ }
}
diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php
index a1e1e7e6b..d791c64ca 100644
--- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php
+++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-profiles-itil/UserProfilesEventListenerTest.php
@@ -65,14 +65,14 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
'Portal user',
]
],
- 'Portal power user + Support Agent => profiles untouched' => [
+ 'Portal power user + Configuration Manager => profiles untouched' => [
'aAssociatedProfilesBeforeUserCreation' => [
'Portal power user',
- 'Support Agent',
+ 'Configuration Manager',
],
'aExpectedAssociatedProfilesAfterUserCreation'=> [
'Portal power user',
- 'Support Agent',
+ 'Configuration Manager',
]
],
];
@@ -89,7 +89,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser->Set('login', $sLogin);
$oUser->Set('password', 'ABCD1234@gabuzomeu');
$oUser->Set('language', 'EN US');
- $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserCreationTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
/**
@@ -103,7 +103,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser->Set('login', $sLogin);
$oUser->Set('password', 'ABCD1234@gabuzomeu');
$oUser->Set('language', 'EN US');
- $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserUpdateTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
/**
@@ -115,7 +115,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser = new \UserLDAP();
$sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid();
$oUser->Set('login', $sLogin);
- $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserCreationTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
/**
@@ -127,7 +127,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser = new \UserLDAP();
$sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
$oUser->Set('login', $sLogin);
- $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserUpdateTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
/**
@@ -139,7 +139,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser = new \UserExternal();
$sLogin = 'testUserLDAPCreationWithPortalPowerUserProfile-'.uniqid();
$oUser->Set('login', $sLogin);
- $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserCreationTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
/**
@@ -151,7 +151,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser = new \UserExternal();
$sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
$oUser->Set('login', $sLogin);
- $this->commonUserUpdate($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->commonUserUpdateTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aExpectedAssociatedProfilesAfterUserCreation);
}
public function CreateUserForProfileTesting(\User $oUserToCreate, array $aAssociatedProfilesBeforeUserCreation, $bDbInsert=true) : array
@@ -189,16 +189,16 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
return [ $sId, $aProfiles];
}
- public function commonUserCreation($oUserToCreate, $aAssociatedProfilesBeforeUserCreation,
+ public function commonUserCreationTest($oUserToCreate, $aAssociatedProfilesBeforeUserCreation,
$aExpectedAssociatedProfilesAfterUserCreation, $bTestUserItopAccess=true)
{
$sUserClass = get_class($oUserToCreate);
list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUserToCreate, $aAssociatedProfilesBeforeUserCreation);
- $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation, $bTestUserItopAccess);
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation, $bTestUserItopAccess);
}
- public function CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation, $bTestUserItopAccess=true){
+ public function CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation, $bTestItopConnection=true){
$oUser = \MetaModel::GetObject($sUserClass, $sId);
$oUserProfileList = $oUser->Get('profile_list');
$aProfilesAfterCreation=[];
@@ -211,7 +211,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
"profile \'$sExpectedProfileName\' should be asociated to user after creation. " . var_export($aProfilesAfterCreation, true) );
}
- if (! $bTestUserItopAccess){
+ if (! $bTestItopConnection){
return;
}
@@ -233,7 +233,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$_SESSION = [];
}
- public function commonUserUpdate($oUserToCreate, $aAssociatedProfilesBeforeUserCreation,
+ public function commonUserUpdateTest($oUserToCreate, $aAssociatedProfilesBeforeUserCreation,
$aExpectedAssociatedProfilesAfterUserCreation)
{
$sUserClass = get_class($oUserToCreate);
@@ -256,11 +256,14 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUserToUpdate->Set('profile_list', $oProfileList);
$oUserToUpdate->DBWrite();
- $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation);
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedAssociatedProfilesAfterUserCreation);
}
- public function testUpdateUserExternalProfilesViaLinks(){
- $aInitialProfiles = [ "Administrator", "Portal power user"];
+ /**
+ * @dataProvider ProfilesLinksProvider
+ */
+ public function testProfilesLinksDBDelete(string $sProfileNameToRemove, $bRaiseException=false){
+ $aInitialProfiles = [ $sProfileNameToRemove, "Portal power user"];
$oUser = new \UserExternal();
$sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
@@ -269,70 +272,66 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$sUserClass = get_class($oUser);
list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles);
+ if ($bRaiseException){
+ $this->expectException(\DeleteException::class);
+ }
+
$aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId);
- $sProfileNameToRemove = "Administrator";
if (array_key_exists($sProfileNameToRemove, $aURPUserProfileByUser)){
$oURPUserProfile = $aURPUserProfileByUser[$sProfileNameToRemove];
$oURPUserProfile->DBDelete();
}
- $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"];
- $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate);
+ if (! $bRaiseException) {
+ $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"];
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedProfilesAfterUpdate);
+ }
}
- public function BulkUpdateUserExternalProfilesViaLinksProvider(){
+ /**
+ * @dataProvider ProfilesLinksProvider
+ */
+ public function testProfilesLinksEdit_ChangeProfileId(string $sInitialProfile, $bRaiseException=false){
+ $oUser = new \UserExternal();
+ $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
+ $oUser->Set('login', $sLogin);
+
+ $sUserClass = get_class($oUser);
+ list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, [$sInitialProfile]);
+
+ $oURP_Profile = \MetaModel::GetObjectByColumn("URP_Profiles", "name", "Portal power user");
+
+ $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId);
+
+ if ($bRaiseException){
+ $this->expectException(\CoreCannotSaveObjectException::class);
+ }
+
+ if (array_key_exists($sInitialProfile, $aURPUserProfileByUser)){
+ $oURPUserProfile = $aURPUserProfileByUser[$sInitialProfile];
+ $oURPUserProfile->Set('profileid', $oURP_Profile->GetKey());
+ $oURPUserProfile->DBWrite();
+ }
+
+ if (!$bRaiseException) {
+ $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"];
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedProfilesAfterUpdate);
+ }
+ }
+
+ public function ProfilesLinksProvider() {
return [
- 'user profiles REPAIR 1' => [
- "aInitialProfiles" => [ "Administrator"],
- "aOperation" => [
- '-Administrator',
- '+Portal power user',
- ],
- "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"],
- ],
- 'user profiles REPAIR 2' => [
- "aInitialProfiles" => [ "Administrator"],
- "aOperation" => [
- '+Portal power user',
- '-Administrator',
- ],
- "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"],
- ],
- 'user profiles REPAIR 3' => [
- "aInitialProfiles" => [ "Administrator", "Portal power user"],
- "aOperation" => [
- '-Administrator',
- ],
- "aExpectedProfilesAfterUpdate" => ["Portal power user", "Portal user"],
- ],
- 'NOTHING DONE with 1 profile' => [
- "aInitialProfiles" => [ "Administrator", "Portal power user"],
- "aOperation" => [
- '-Portal power user',
- ],
- "aExpectedProfilesAfterUpdate" => ["Administrator"],
- ],
- 'NOTHING DONE with 2 profiles including power...' => [
- "aInitialProfiles" => [ "Administrator"],
- "aOperation" => [
- '+Portal power user',
- ],
- "aExpectedProfilesAfterUpdate" => ["Administrator", "Portal power user"],
- ],
- 'NOTHING DONE with 2 profiles including power again ...' => [
- "aInitialProfiles" => [ "Portal user"],
- "aOperation" => [
- '+Portal power user',
- ],
- "aExpectedProfilesAfterUpdate" => ["Portal user", "Portal power user"],
- ],
+ "Administrator" => [ "sProfileNameToMove" => "Administrator" ],
+ "Portal user" => [ "sProfileNameToMove" => "Portal user", "bRaiseException" => true ],
];
}
/**
- * @dataProvider BulkUpdateUserExternalProfilesViaLinksProvider
+ * @dataProvider ProfilesLinksProvider
*/
- public function testBulkUpdateUserExternalProfilesViaLinks($aInitialProfiles, $aOperation, $aExpectedProfilesAfterUpdate){
+ public function testProfilesLinksEdit_ChangeUserId($sProfileNameToMove, $bRaiseException=false){
+ $aInitialProfiles = [ $sProfileNameToMove, "Portal power user"];
+
$oUser = new \UserExternal();
$sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
$oUser->Set('login', $sLogin);
@@ -340,31 +339,29 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$sUserClass = get_class($oUser);
list ($sId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, $aInitialProfiles);
- \cmdbAbstractObject::SetEventDBLinksChangedBlocked(true);
+ $oUser = new \UserExternal();
+ $sLogin = 'testUserLDAPUpdateWithPortalPowerUserProfile-'.uniqid();
+ $oUser->Set('login', $sLogin);
+ list ($sAnotherUserId, $aProfiles) = $this->CreateUserForProfileTesting($oUser, ["Configuration Manager"]);
- $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId);
- foreach ($aOperation as $sOperation){
- $sOp = substr($sOperation,0, 1);
- $sProfileName = substr($sOperation,1);
-
- if ($sOp === "-"){
- if (array_key_exists($sProfileName, $aURPUserProfileByUser)){
- $oURPUserProfile = $aURPUserProfileByUser[$sProfileName];
- $oURPUserProfile->DBDelete();
- }
- } else {
- $oAdminUrpProfile = new URP_UserProfile();
- $oProfile = $aProfiles[$sProfileName];
- $oAdminUrpProfile->Set('profileid', $oProfile->GetKey());
- $oAdminUrpProfile->Set('userid', $sId);
- $oAdminUrpProfile->DBInsert();
- }
+ if ($bRaiseException){
+ $this->expectException(\CoreCannotSaveObjectException::class);
}
- \cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
- \cmdbAbstractObject::FireEventDbLinksChangedForAllObjects();
+ $aURPUserProfileByUser = $this->GetURPUserProfileByUser($sId);
+ if (array_key_exists($sProfileNameToMove, $aURPUserProfileByUser)){
+ $oURPUserProfile = $aURPUserProfileByUser[$sProfileNameToMove];
+ $oURPUserProfile->Set('userid', $sAnotherUserId);
+ $oURPUserProfile->DBWrite();
+ }
- $this->CheckProfilesAreOk($sUserClass, $sId, $aExpectedProfilesAfterUpdate);
+ if (! $bRaiseException) {
+ $aExpectedProfilesAfterUpdate = [$sProfileNameToMove, "Configuration Manager"];
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sAnotherUserId, $aExpectedProfilesAfterUpdate);
+
+ $aExpectedProfilesAfterUpdate = ["Portal power user", "Portal user"];
+ $this->CheckProfilesAreOkAndThenConnectToITop($sUserClass, $sId, $aExpectedProfilesAfterUpdate);
+ }
}
private function GetURPUserProfileByUser($iUserId) : array {
@@ -461,7 +458,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
public function testInit_ConfWithOneWarningProfile() {
\MetaModel::GetConfig()->Set(UserProfilesEventListener::USERPROFILE_REPAIR_ITOP_PARAM_NAME,
- ['Change Supervisor' => 'Administrator', 'Portal power user' => null]
+ ['Ticket Manager' => 'Administrator', 'Portal power user' => null]
);
$oUserProfilesEventListener = new UserProfilesEventListener();
$oUserProfilesEventListener->Init();
@@ -470,7 +467,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
public function testInit_ConfWithFurtherWarningProfiles() {
\MetaModel::GetConfig()->Set(UserProfilesEventListener::USERPROFILE_REPAIR_ITOP_PARAM_NAME,
- ['Change Supervisor' => null, 'Portal power user' => null]
+ ['Ticket Manager' => null, 'Portal power user' => null]
);
$oUserProfilesEventListener = new UserProfilesEventListener();
$oUserProfilesEventListener->Init();
@@ -479,7 +476,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
public function testInit_ConfWithFurtherWarningProfilesAndOneRepairment() {
\MetaModel::GetConfig()->Set(UserProfilesEventListener::USERPROFILE_REPAIR_ITOP_PARAM_NAME,
- ['Portal power user' => null, 'Change Supervisor' => null, 'Administrator' => "REST Services User"]
+ ['Portal power user' => null, 'Ticket Manager' => null, 'Administrator' => "Configuration Manager"]
);
$oUserProfilesEventListener = new UserProfilesEventListener();
$oUserProfilesEventListener->Init();
@@ -495,14 +492,14 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser->Set('language', 'EN US');
\MetaModel::GetConfig()->Set(UserProfilesEventListener::USERPROFILE_REPAIR_ITOP_PARAM_NAME,
- ['Portal power user' => 'Change Supervisor']
+ ['Portal power user' => 'Ticket Manager']
);
$oUserProfilesEventListener = new UserProfilesEventListener();
$oUserProfilesEventListener->Init();
$this->assertTrue($oUserProfilesEventListener->IsRepairmentEnabled());
$this->CreateUserForProfileTesting($oUser, ['Portal power user'], false);
- $oUserProfilesEventListener->RepairProfiles($oUser);
+ $oUserProfilesEventListener->ValidateThenRepairOrWarn($oUser);
$oUserProfileList = $oUser->Get('profile_list');
$aProfilesAfterCreation=[];
@@ -510,7 +507,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$aProfilesAfterCreation[] = $oProfile->Get('profile');
}
- $this->assertContains('Change Supervisor', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
+ $this->assertContains('Ticket Manager', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
$this->assertContains('Portal power user', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
}
@@ -518,8 +515,8 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
{
\MetaModel::GetConfig()->Set(UserProfilesEventListener::USERPROFILE_REPAIR_ITOP_PARAM_NAME,
[
- 'Administrator' => 'REST Services User',
- 'Portal power user' => 'Change Supervisor'
+ 'Administrator' => 'Configuration Manager',
+ 'Portal power user' => 'Ticket Manager'
]
);
$oUserProfilesEventListener = new UserProfilesEventListener();
@@ -532,7 +529,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser->Set('password', 'ABCD1234@gabuzomeu');
$oUser->Set('language', 'EN US');
$this->CreateUserForProfileTesting($oUser, ['Portal power user'], false);
- $oUserProfilesEventListener->RepairProfiles($oUser);
+ $oUserProfilesEventListener->ValidateThenRepairOrWarn($oUser);
$oUserProfileList = $oUser->Get('profile_list');
$aProfilesAfterCreation=[];
@@ -540,7 +537,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$aProfilesAfterCreation[] = $oProfile->Get('profile');
}
- $this->assertContains('Change Supervisor', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
+ $this->assertContains('Ticket Manager', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
$this->assertContains('Portal power user', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
$oUser2 = new \UserLocal();
@@ -550,7 +547,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUser2->Set('language', 'EN US');
$this->CreateUserForProfileTesting($oUser2, ['Administrator'], false);
- $oUserProfilesEventListener->RepairProfiles($oUser2);
+ $oUserProfilesEventListener->ValidateThenRepairOrWarn($oUser2);
$oUserProfileList = $oUser2->Get('profile_list');
$aProfilesAfterCreation=[];
@@ -559,7 +556,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
}
$this->assertContains('Administrator', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
- $this->assertContains('REST Services User', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
+ $this->assertContains('Configuration Manager', $aProfilesAfterCreation, var_export($aProfilesAfterCreation, true));
}
public function testUserCreationWithWarningMessageConf()
@@ -571,11 +568,9 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oAdminUser->Set('password', 'ABCD1234@gabuzomeu');
$oAdminUser->Set('language', 'EN US');
$aAssociatedProfilesBeforeUserCreation = ['Administrator'];
- $this->commonUserCreation($oAdminUser, $aAssociatedProfilesBeforeUserCreation, $aAssociatedProfilesBeforeUserCreation, false);
+ $this->commonUserCreationTest($oAdminUser, $aAssociatedProfilesBeforeUserCreation, $aAssociatedProfilesBeforeUserCreation, false);
UserRights::Login($oAdminUser->Get('login'));
-
-
$aAssociatedProfilesBeforeUserCreation = [
'Portal power user'
];
@@ -594,8 +589,11 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
$oUserProfilesEventListener = new UserProfilesEventListener();
$oUserProfilesEventListener->RegisterEventsAndListeners();
- $this->commonUserCreation($oUser, $aAssociatedProfilesBeforeUserCreation, $aAssociatedProfilesBeforeUserCreation, false);
- $aObjMessages = Session::Get('obj_messages');
+ $this->expectException(\CoreCannotSaveObjectException::class);
+
+ $this->commonUserCreationTest($oUser, $aAssociatedProfilesBeforeUserCreation, $aAssociatedProfilesBeforeUserCreation, false);
+
+ /*$aObjMessages = Session::Get('obj_messages');
$this->assertNotEmpty($aObjMessages);
$sKey = sprintf("%s::%s", get_class($oUser), $oUser->GetKey());
$this->assertTrue(array_key_exists($sKey, $aObjMessages));
@@ -608,7 +606,7 @@ class UserProfilesEventListenerTest extends ItopDataTestCase
]
];
$this->assertEquals($aExpectedMessages, array_values($aObjMessages[$sKey]), var_export($aObjMessages[$sKey], true));
-
+*/
$_SESSION = [];
}
}