diff --git a/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php b/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php index bfc6ab20148a06bc8273a569e84c4cd442193b62..b0a7d73a99bf0ed3185479457d6f2f157294f427 100644 --- a/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php +++ b/typo3/sysext/core/Classes/Type/Bitmask/JsConfirmation.php @@ -52,6 +52,9 @@ class JsConfirmation extends Enumeration */ const ALL = 255; + /** + * @var int + */ const __default = self::ALL; /** @@ -84,13 +87,7 @@ class JsConfirmation extends Enumeration */ protected function setValue($value) { - if ($value < 255) { - if (($value & self::$allowedValues) !== $value) { - throw new Exception\InvalidEnumerationValueException( - sprintf('Invalid value %s for %s', $value, __CLASS__), - 1457175152 - ); - } + if ($this->isValid($value)) { $this->value = $value; } else { parent::setValue($value); @@ -106,15 +103,10 @@ class JsConfirmation extends Enumeration protected function isValid($value) { if ($value < 255) { - return ($value & self::$allowedValues) === $value; - } - - $value = (string)$value; - foreach (static::$enumConstants[static::class] as $constantValue) { - if ($value === (string)$constantValue) { - return true; - } + // Check for combined bitmask or bitmask with bits unset from self::ALL + $unsetValues = (self::ALL ^ $value); + return ($value & self::$allowedValues) === $value || $unsetValues === ($unsetValues & self::$allowedValues); } - return false; + return parent::isValid($value); } } diff --git a/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php b/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php index 235b0823fbc7f27d88f2615f9caa04e264ae0773..a8266796cb53300a33018e56a85c8297e955f3ea 100644 --- a/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php +++ b/typo3/sysext/core/Tests/Unit/Authentication/BackendUserAuthenticationTest.php @@ -743,6 +743,56 @@ class BackendUserAuthenticationTest extends UnitTestCase $this->assertTrue($subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)); } + /** + * @test + * @dataProvider jsConfirmationsWithUnsetBits + * + * @param int $jsConfirmation + * @param int $typeChangeAllowed + * @param int $copyMovePasteAllowed + * @param int $deleteAllowed + * @param int $feEditAllowed + * @param int $otherAllowed + */ + public function jsConfirmationAllowsUnsettingBitsInValue($jsConfirmation, $typeChangeAllowed, $copyMovePasteAllowed, $deleteAllowed, $feEditAllowed, $otherAllowed) + { + $subject = $this->getMockBuilder(BackendUserAuthentication::class) + ->setMethods(['getTSConfig']) + ->getMock(); + $subject->method('getTSConfig')->with('options.alertPopups')->willReturn(['value' => $jsConfirmation]); + + $this->assertEquals($typeChangeAllowed, $subject->jsConfirmation(JsConfirmation::TYPE_CHANGE)); + $this->assertEquals($copyMovePasteAllowed, $subject->jsConfirmation(JsConfirmation::COPY_MOVE_PASTE)); + $this->assertEquals($deleteAllowed, $subject->jsConfirmation(JsConfirmation::DELETE)); + $this->assertEquals($feEditAllowed, $subject->jsConfirmation(JsConfirmation::FE_EDIT)); + $this->assertEquals($otherAllowed, $subject->jsConfirmation(JsConfirmation::OTHER)); + } + + /** + * @return array + */ + public function jsConfirmationsWithUnsetBits() + { + return [ + 'All except "type change" and "copy/move/paste"' => [ + 252, + false, + false, + true, + true, + true, + ], + 'All except "other"' => [ + 127, + true, + true, + true, + true, + false, + ], + ]; + } + /** * @test */