From 9bc88208cce69f80223c5d5c68055d3c634f2d2f Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Sun, 14 Jan 2018 08:23:17 +0100 Subject: [PATCH] Add acl form field See #2509 --- .../files/acp/templates/__aclFormField.tpl | 9 + .../files/lib/system/acl/ACLHandler.class.php | 61 +++++- .../form/builder/field/AclFormField.class.php | 205 ++++++++++++++++++ 3 files changed, 273 insertions(+), 2 deletions(-) create mode 100644 wcfsetup/install/files/acp/templates/__aclFormField.tpl create mode 100644 wcfsetup/install/files/lib/system/form/builder/field/AclFormField.class.php diff --git a/wcfsetup/install/files/acp/templates/__aclFormField.tpl b/wcfsetup/install/files/acp/templates/__aclFormField.tpl new file mode 100644 index 0000000000..16b053dcbc --- /dev/null +++ b/wcfsetup/install/files/acp/templates/__aclFormField.tpl @@ -0,0 +1,9 @@ +{include file='__formFieldHeader'} + +{if $includeAclJavaScript} + {include file='aclPermissions'} +{/if} + +{include file='aclPermissionJavaScript' containerID=$field->getPrefixedId()|concat:'Container' categoryName=$field->getCategoryName() objectID=$field->getObjectID() objectTypeID=$field->getObjectType()->objectTypeID} + +{include file='__formFieldFooter'} diff --git a/wcfsetup/install/files/lib/system/acl/ACLHandler.class.php b/wcfsetup/install/files/lib/system/acl/ACLHandler.class.php index bc225d6a2b..8a55f4c97f 100644 --- a/wcfsetup/install/files/lib/system/acl/ACLHandler.class.php +++ b/wcfsetup/install/files/lib/system/acl/ACLHandler.class.php @@ -41,6 +41,13 @@ class ACLHandler extends SingletonFactory { */ protected $categories = []; + /** + * explicitly read acl values grouped by object type id + * @var array + * @see ACLHandler::readValues() + */ + protected $__readValues = []; + /** * Assigns the acl values to the template. * @@ -51,9 +58,15 @@ class ACLHandler extends SingletonFactory { WCF::getTPL()->assign('aclValues', []); } - if (!$this->assignVariablesDisabled && isset($_POST['aclValues'])) { + $values = null; + if (isset($this->__readValues[$objectTypeID])) { + $values = $this->__readValues[$objectTypeID]; + } + else if (isset($_POST['aclValues'])) { $values = $_POST['aclValues']; - + } + + if (!$this->assignVariablesDisabled && $values !== null) { $data = $this->getPermissions($objectTypeID, [], null, true); $users = []; @@ -112,6 +125,50 @@ class ACLHandler extends SingletonFactory { $this->assignVariablesDisabled = false; } + /** + * Reads the values for the given object type id. + * + * Note: This method primarily only exists for form builder. If you are not + * using form builder, you do not need this method. + * + * @param integer $objectTypeID + */ + public function readValues($objectTypeID) { + $this->__readValues[$objectTypeID] = []; + + if (isset($_POST['aclValues'])) { + $options = ACLOption::getOptions($objectTypeID)->getObjects(); + + foreach (['group', 'user'] as $type) { + if (isset($_POST['aclValues'][$type])) { + $this->__readValues[$objectTypeID][$type] = []; + + foreach ($_POST['aclValues'][$type] as $typeID => $optionData) { + $this->__readValues[$objectTypeID][$type][$typeID] = []; + + foreach ($optionData as $optionID => $optionValue) { + if (isset($options[$optionID])) { + $this->__readValues[$objectTypeID][$type][$typeID][$optionID] = $optionValue; + } + } + } + } + } + } + } + + /** + * Resets the acl values read by `readValues()` for the given object type id. + * + * Note: This method primarily only exists for form builder. If you are not + * using form builder, you do not need this method. + * + * @param integer $objectTypeID + */ + public function resetValues($objectTypeID) { + $this->__readValues[$objectTypeID] = []; + } + /** * @inheritDoc */ diff --git a/wcfsetup/install/files/lib/system/form/builder/field/AclFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/AclFormField.class.php new file mode 100644 index 0000000000..cb44811496 --- /dev/null +++ b/wcfsetup/install/files/lib/system/form/builder/field/AclFormField.class.php @@ -0,0 +1,205 @@ + + * @package WoltLabSuite\Core\System\Form\Builder\Field + * @since 3.2 + */ +class AclFormField extends AbstractFormField { + /** + * name of/filter for the name(s) of the shown acl option categories + * @var null|string + */ + protected $__categoryName; + + /** + * id of the edited object or null if no object is edited + * @var null|int + */ + protected $__objectID; + + /** + * acl object type + * @var null|ObjectType + */ + protected $__objectType; + + /** + * @inheritDoc + */ + protected $templateName = '__aclFormField'; + + /** + * is `true` if acl-related global JavaScript code has already been included + * and is `false` otherwise + * @var bool + */ + protected static $includedAclJavaScript = false; + + /** + * Sets the name of/filter for the name(s) of the shown acl option categories and + * returns this field. + * + * @param string $categoryName name of/filter for the acl option categories + * @return static $this this field + * + * @throws \InvalidArgumentException if given category name is no string or otherwise invalid + */ + public function categoryName($categoryName) { + if (!is_string($categoryName)) { + throw new \InvalidArgumentException("Given category name is no string, '" . gettype($categoryName) . "' given."); + } + + $this->__categoryName = $categoryName; + + return $this; + } + + /** + * Returns the name of/filter for the name(s) of the shown acl option categories + * or returns `null` if no category name has been set. + * + * @return null|string + */ + public function getCategoryName() { + return $this->__categoryName; + } + + /** + * @inheritDoc + */ + public function getHtmlVariables() { + ACLHandler::getInstance()->assignVariables($this->getObjectType()->objectTypeID); + + $includeAclJavaScript = !static::$includedAclJavaScript; + if (!static::$includedAclJavaScript) { + static::$includedAclJavaScript = true; + } + + return [ + 'includeAclJavaScript' => $includeAclJavaScript + ]; + } + + /** + * Returns the id of the edited object or `null` if no object is edited. + * + * @return null|int + */ + public function getObjectID() { + return $this->__objectID; + } + + /** + * Returns the acl object type. + * + * @return ObjectType acl object type + * + * @throws \BadMethodCallException if object type has not been set + */ + public function getObjectType() { + if ($this->__objectType === null) { + throw new \BadMethodCallException("Object type has not been set."); + } + + return $this->__objectType; + } + + /** + * @inheritDoc + */ + public function hasSaveValue() { + return false; + } + + /** + * Sets the id of the edited object and returns this field. + * + * If no object is edited, this method must not be called. + * + * @param int $objectID id of edited object + * @return static $this this field + * + * @throws \BadMethodCallException if object id has already been set + * @throws \InvalidArgumentException if given object id is no integer or otherwise invalid + */ + public function objectID($objectID) { + if ($this->__objectID !== null) { + throw new \BadMethodCallException("Object id has already been set."); + } + + if (!is_int($objectID)) { + throw new \InvalidArgumentException("Given object id is no integer, '" . gettype($objectID) . "' given."); + } + + if ($objectID <= 0) { + throw new \InvalidArgumentException("Given object id is not positive"); + } + + $this->__objectID = $objectID; + + return $this; + } + + /** + * Sets the name of the acl object type and returns this field. + * + * @param string $objectType acl object type name + * @return static this field + * + * @throws \BadMethodCallException if object type has already been set + * @throws \InvalidArgumentException if given object type name is no string or otherwise invalid + */ + public function objectType($objectType) { + if ($this->__objectType !== null) { + throw new \BadMethodCallException("Object type has already been set."); + } + + if (!is_string($objectType)) { + throw new \InvalidArgumentException("Given object type name is no string, '" . gettype($objectType) . "' given."); + } + + try { + $this->__objectType = ObjectTypeCache::getInstance()->getObjectType(ACLHandler::getInstance()->getObjectTypeID($objectType)); + } + catch (SystemException $e) { + throw new \InvalidArgumentException("Given object type name is no valid acl object type."); + } + + // reset old values from previous request + ACLHandler::getInstance()->resetValues($this->__objectType->objectTypeID); + + return $this; + } + + /** + * @inheritDoc + */ + public function populate() { + $this->getDocument()->getDataHandler()->add(new CustomFormFieldDataProcessor('acl', function(IFormDocument $document, array $parameters) { + $parameters['aclObjectTypeID'] = $this->getObjectType()->objectTypeID; + + return $parameters; + })); + + return $this; + } + + /** + * @inheritDoc + */ + public function readValue() { + ACLHandler::getInstance()->readValues($this->getObjectType()->objectTypeID); + } +} -- 2.20.1