diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index 35e172385..4e4ed34b5 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -1726,6 +1726,15 @@ class AttributeLinkedSet extends AttributeDefinition
return $sDisplayStyle;
}
+ /**
+ * @return bool true if host object has constraints
+ * @since 3.1.0 N°6228
+ */
+ public function GetHasConstraint()
+ {
+ return $this->GetOptional('with_constrain', false);
+ }
+
/**
* @return boolean
* @since 3.1.0 N°5563
diff --git a/core/datamodel.core.xml b/core/datamodel.core.xml
index 68e0c3ff6..05ab9fba1 100644
--- a/core/datamodel.core.xml
+++ b/core/datamodel.core.xml
@@ -482,6 +482,12 @@
boolean
true
+
+ with_constrain
+ false
+ boolean
+ false
+
on_target_delete
false
diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php
index 3cfa444dd..a35dfb3bd 100644
--- a/core/userrights.class.inc.php
+++ b/core/userrights.class.inc.php
@@ -248,9 +248,8 @@ abstract class User extends cmdbAbstractObject
"depends_on" => array(),
)));
- MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",
- array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
- MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array())));
+ MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_constrain" => true)));
+ MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_constrain' => true)));
MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false)));
// Display lists
diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php
index f8ad07896..b1f5d338e 100644
--- a/setup/compiler.class.inc.php
+++ b/setup/compiler.class.inc.php
@@ -2064,6 +2064,7 @@ EOF
$this->CompileCommonProperty('display_style', $oField, $aParameters, $sModuleRelativeDir);
$this->CompileCommonProperty('filter', $oField, $aParameters, $sModuleRelativeDir);
$this->CompileCommonProperty('allowed_values', $oField, $aParameters, $sModuleRelativeDir);
+ $this->CompileCommonProperty('with_constrain', $oField, $aParameters, $sModuleRelativeDir, false);
$aParameters['depends_on'] = $sDependencies;
} elseif ($sAttType == 'AttributeLinkedSet') {
$this->CompileCommonProperty('linked_class', $oField, $aParameters, $sModuleRelativeDir);
@@ -2073,6 +2074,7 @@ EOF
$this->CompileCommonProperty('display_style', $oField, $aParameters, $sModuleRelativeDir);
$this->CompileCommonProperty('edit_mode', $oField, $aParameters, $sModuleRelativeDir);
$this->CompileCommonProperty('filter', $oField, $aParameters, $sModuleRelativeDir);
+ $this->CompileCommonProperty('with_constrain', $oField, $aParameters, $sModuleRelativeDir, false);
$aParameters['depends_on'] = $sDependencies;
} elseif ($sAttType == 'AttributeExternalKey') {
$this->CompileCommonProperty('target_class', $oField, $aParameters, $sModuleRelativeDir);
diff --git a/setup/itopdesignformat.class.inc.php b/setup/itopdesignformat.class.inc.php
index ecf4be546..1b0db8799 100644
--- a/setup/itopdesignformat.class.inc.php
+++ b/setup/itopdesignformat.class.inc.php
@@ -1132,6 +1132,11 @@ class iTopDesignFormat
$this->RemoveNodeFromXPath("/itop_design/classes//class/fields/field[@xsi:type='AttributeLinkedSet']/display_style");
$this->RemoveNodeFromXPath("/itop_design/classes//class/fields/field[@xsi:type='AttributeLinkedSetIndirect']/display_style");
+ // N°6228 - Remove last Profil of a User / Exceed SaaS User quota without control
+ // - Remove with_constrain
+ $this->RemoveNodeFromXPath("/itop_design/classes//class/fields/field[@xsi:type='AttributeLinkedSet']/with_constrain");
+ $this->RemoveNodeFromXPath("/itop_design/classes//class/fields/field[@xsi:type='AttributeLinkedSetIndirect']/with_constrain");
+
// N°2783 - Custom zlists
$this->RemoveNodeFromXPath("/itop_design/classes//class/presentation/custom_presentations");
$this->RemoveNodeFromXPath("/itop_design/meta/presentation/custom_presentations");
diff --git a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php
index cc827109d..0b4cc29e4 100644
--- a/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php
+++ b/tests/php-unit-tests/unitary-tests/core/UserRightsTest.php
@@ -527,4 +527,29 @@ class UserRightsTest extends ItopDataTestCase
'with Admins hidden' => [true, 0],
];
}
+
+ /**
+ * @dataProvider WithConstraintParameterProvider
+ * @param string $sClass
+ * @param string $sAttCode
+ * @param bool $bExpected
+ *
+ * @return void
+ * @throws \Exception
+ */
+ public function testWithConstraintParameter(string $sClass, string $sAttCode, bool $bExpected)
+ {
+ $oAttDef = \MetaModel::GetAttributeDef($sClass, $sAttCode);
+ $this->assertTrue(method_exists($oAttDef, "GetHasConstraint"));
+ $this->assertEquals($bExpected, $oAttDef->GetHasConstraint());
+ }
+
+ public function WithConstraintParameterProvider()
+ {
+ return [
+ ['User', 'profile_list', true],
+ ['User', 'allowed_org_list', true],
+ ['Person', 'team_list', false],
+ ];
+ }
}
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.expected.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.expected.xml
index c11c89290..e22d6a4c5 100644
--- a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.expected.xml
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.expected.xml
@@ -61,6 +61,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.input.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.input.xml
index 7212ef465..a5f29dd3e 100644
--- a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.input.xml
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.0.input.xml
@@ -89,6 +89,20 @@
+
+
+
+ true
+
+
+
+
+
+
+ true
+
+
+