Added a simplified ACL system
authorAlexander Ebert <ebert@woltlab.com>
Thu, 23 Jun 2016 13:30:47 +0000 (15:30 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 23 Jun 2016 13:30:47 +0000 (15:30 +0200)
The already existing ACL implementation relies on various options to
provide access controls to objects. This is great, but is a bit too much
for objects that just want a simple yes/no for access based on groups
and users.

15 files changed:
com.woltlab.wcf/objectType.xml
com.woltlab.wcf/objectTypeDefinition.xml
wcfsetup/install/files/acp/templates/aclSimple.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/pageAdd.tpl
wcfsetup/install/files/js/WoltLab/WCF/Ui/Acl/Simple.js [new file with mode: 0644]
wcfsetup/install/files/js/WoltLab/WCF/Ui/User/Search/Input.js
wcfsetup/install/files/lib/acp/form/PageAddForm.class.php
wcfsetup/install/files/lib/acp/form/PageEditForm.class.php
wcfsetup/install/files/lib/data/user/group/UserGroup.class.php
wcfsetup/install/files/lib/system/acl/simple/SimpleAclHandler.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/acl/simple/SimpleAclResolver.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/cache/builder/SimpleAclCacheBuilder.class.php [new file with mode: 0644]
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index 645096dc6ac774fffcadfa9f679fad1402f4ff48..27a33f2368e19fa7e4e7200e95e059b05a1f386c 100644 (file)
                </type>
                <!-- /box controllers -->
                
+               <!-- pages -->
+               <type>
+                       <name>com.woltlab.wcf.page</name>
+                       <definitionname>com.woltlab.wcf.acl.simple</definitionname>
+               </type>
+               <!-- /pages -->
+               
                <!-- deprecated -->
                <type>
                        <name>com.woltlab.wcf.page.controller</name>
index 26c32bbeef2056ded4abeed5c5c642f131a8ed56..792d01008cba44fa427104eea4a0a3c91145a485 100644 (file)
@@ -5,6 +5,10 @@
                        <name>com.woltlab.wcf.acl</name>
                </definition>
                
+               <definition>
+                       <name>com.woltlab.wcf.acl.simple</name>
+               </definition>
+               
                <definition>
                        <name>com.woltlab.wcf.collapsibleContent</name>
                </definition>
diff --git a/wcfsetup/install/files/acp/templates/aclSimple.tpl b/wcfsetup/install/files/acp/templates/aclSimple.tpl
new file mode 100644 (file)
index 0000000..35a2d2b
--- /dev/null
@@ -0,0 +1,57 @@
+<div class="section">
+       <dl>
+               <dt><label for="aclAllowAll">{lang}wcf.acl.allowAll{/lang}</label></dt>
+               <dd>
+                       <ol class="flexibleButtonGroup">
+                               <li>
+                                       <input type="radio" id="aclAllowAll" name="aclValues[allowAll]" value="1"{if $aclValues[allowAll]} checked{/if}>
+                                       <label for="aclAllowAll" class="green"><span class="icon icon16 fa-check"></span> {lang}wcf.acp.option.type.boolean.yes{/lang}</label>
+                               </li>
+                               <li>
+                                       <input type="radio" id="aclAllowAll_no" name="aclValues[allowAll]" value="0"{if !$aclValues[allowAll]} checked{/if}>
+                                       <label for="aclAllowAll_no" class="red"><span class="icon icon16 fa-times"></span> {lang}wcf.acp.option.type.boolean.no{/lang}</label>
+                               </li>
+                       </ol>
+               </dd>
+       </dl>
+</div>
+
+<section class="section" id="aclInputContainer"{if $aclValues[allowAll]} style="display: none;"{/if}>
+       <h2 class="sectionTitle">{lang}wcf.acl.access{/lang}</h2>
+       <dl>
+               <dt><label for="aclSearchInput">{lang}wcf.acl.access.grant{/lang}</label></dt>
+               <dd>
+                       <input type="text" id="aclSearchInput" class="long" placeholder="{lang}wcf.acl.search.description{/lang}">
+               </dd>
+       </dl>
+       
+       <dl id="aclListContainer"{if $aclValues[allowAll]} style="display: none;"{/if}>
+               <dt>{lang}wcf.acl.access.granted{/lang}</dt>
+               <dd>
+                       <ul id="aclAccessList" class="aclList containerList">
+                               {foreach from=$aclValues[group] item=aclGroup}
+                                       <li>
+                                               <span class="icon icon16 fa-users"></span>
+                                               <span class="aclLabel">{$aclGroup}</span>
+                                               <span class="icon icon16 fa-times pointer jsTooltip" title="{lang}wcf.global.button.delete{/lang}"></span>
+                                               <input type="hidden" name="aclValues[group][]" value="{@$aclGroup->groupID}">
+                                       </li>
+                               {/foreach}
+                               {foreach from=$aclValues[user] item=aclUser}
+                                       <li>
+                                               <span class="icon icon16 fa-user"></span>
+                                               <span class="aclLabel">{$aclUser}</span>
+                                               <span class="icon icon16 fa-times pointer jsTooltip" title="{lang}wcf.global.button.delete{/lang}"></span>
+                                               <input type="hidden" name="aclValues[user][]" value="{@$aclUser->userID}">
+                                       </li>
+                               {/foreach}
+                       </ul>
+               </dd>
+       </dl>
+</section>
+
+<script data-relocate="true">
+       require(['WoltLab/WCF/Ui/Acl/Simple'], function(UiAclSimple) {
+               new UiAclSimple();
+       });
+</script>
index ab2bec8c3a22fe593001e6b1bba7640b6f8bba01..5a132e68dfb53ecdc8e159f6fb09d2d20c13fbe9 100644 (file)
                </div>
                
                <div id="acl" class="tabMenuContent">
+                       {include file='aclSimple'}
                </div>
        </div>  
        
diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Ui/Acl/Simple.js b/wcfsetup/install/files/js/WoltLab/WCF/Ui/Acl/Simple.js
new file mode 100644 (file)
index 0000000..6dd00ad
--- /dev/null
@@ -0,0 +1,72 @@
+define(['Language', 'Dom/ChangeListener', 'WoltLab/WCF/Ui/User/Search/Input'], function(Language, DomChangeListener, UiUserSearchInput) {
+       "use strict";
+       
+       function UiAclSimple() { this.init(); }
+       UiAclSimple.prototype = {
+               init: function() {
+                       this._build();
+               },
+               
+               _build: function () {
+                       var container = elById('aclInputContainer');
+                       
+                       elById('aclAllowAll').addEventListener('change', (function() {
+                               elHide(container);
+                       }));
+                       elById('aclAllowAll_no').addEventListener('change', (function() {
+                               elShow(container);
+                       }));
+                       
+                       new UiUserSearchInput(elById('aclSearchInput'), {
+                               callbackSelect: this._select.bind(this),
+                               includeUserGroups: true,
+                               preventSubmit: true
+                       });
+                       
+                       this._aclListContainer = elById('aclListContainer');
+                       
+                       this._list = elById('aclAccessList');
+                       this._list.addEventListener(WCF_CLICK_EVENT, this._removeItem.bind(this));
+                       
+                       DomChangeListener.trigger();
+               },
+               
+               _select: function(listItem) {
+                       var type = elData(listItem, 'type');
+                       
+                       var html = '<span class="icon icon16 fa-' + (type === 'group' ? 'users' : 'user') + '"></span>';
+                       html += '<span class="aclLabel">' + elData(listItem, 'label') + '</span>';
+                       html += '<span class="icon icon16 fa-times pointer jsTooltip" title="' + Language.get('wcf.global.button.delete') + '"></span>';
+                       html += '<input type="hidden" name="aclValues[' + type + '][]" value="' + elData(listItem, 'object-id') + '">';
+                       
+                       var item = elCreate('li');
+                       item.innerHTML = html;
+                       
+                       var firstUser = elBySel('.fa-user', this._list);
+                       if (firstUser === null) {
+                               this._list.appendChild(item);
+                       }
+                       else {
+                               this._list.insertBefore(item, firstUser.parentNode);
+                       }
+                       
+                       elShow(this._aclListContainer);
+                       
+                       DomChangeListener.trigger();
+                       
+                       return false;
+               },
+               
+               _removeItem: function (event) {
+                       if (event.target.classList.contains('fa-times')) {
+                               elRemove(event.target.parentNode);
+                               
+                               if (this._list.childElementCount === 0) {
+                                       elHide(this._aclListContainer);
+                               }
+                       }
+               }
+       };
+       
+       return UiAclSimple;
+});
index 867651a63e3c128b2b9719872b028f32a7959a87..bf3550baba1a7b0ecf279f7700fad57b154cf40c 100644 (file)
@@ -36,6 +36,7 @@ define(['Core', 'WoltLab/WCF/Ui/Search/Input'], function(Core, UiSearchInput) {
                
                _createListItem: function(item) {
                        var listItem = UiUserSearchInput._super.prototype._createListItem.call(this, item);
+                       elData(listItem, 'type', item.type);
                        
                        var box = elCreate('div');
                        box.className = 'box16';
index ca27cde06ebba90d68f12ff5b30bc9e9c7336529..9764109c5566e70c02320dd4c88095b07230cd6d 100644 (file)
@@ -10,6 +10,7 @@ use wcf\data\page\PageAction;
 use wcf\data\page\PageEditor;
 use wcf\data\page\PageNodeTree;
 use wcf\form\AbstractForm;
+use wcf\system\acl\simple\SimpleAclHandler;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\UserInputException;
 use wcf\system\html\input\HtmlInputProcessor;
@@ -137,6 +138,12 @@ class PageAddForm extends AbstractForm {
         */
        public $boxIDs = [];
        
+       /**
+        * acl values
+        * @var array
+        */
+       public $aclValues = [];
+       
        /**
         * @inheritDoc
         */
@@ -201,6 +208,8 @@ class PageAddForm extends AbstractForm {
                if (isset($_POST['metaDescription']) && is_array($_POST['metaDescription'])) $this->metaDescription = ArrayUtil::trim($_POST['metaDescription']);
                if (isset($_POST['metaKeywords']) && is_array($_POST['metaKeywords'])) $this->metaKeywords = ArrayUtil::trim($_POST['metaKeywords']);
                if (isset($_POST['boxIDs']) && is_array($_POST['boxIDs'])) $this->boxIDs = ArrayUtil::toIntegerArray($_POST['boxIDs']);
+               
+               if (isset($_POST['aclValues']) && is_array($_POST['aclValues'])) $this->aclValues = $_POST['aclValues'];
        }
        
        /**
@@ -377,7 +386,8 @@ class PageAddForm extends AbstractForm {
                $parseHTML = function($content) {
                        if ($this->pageType == 'text') {
                                $htmlInputProcessor = new HtmlInputProcessor();
-                               $content = $htmlInputProcessor->process($content);
+                               $htmlInputProcessor->process($content);
+                               $content = $htmlInputProcessor->getHtml();
                        }
                        
                        return $content;
@@ -425,13 +435,16 @@ class PageAddForm extends AbstractForm {
                // set generic page identifier
                $pageEditor = new PageEditor($page);
                $pageEditor->update([
-                       'identifier' => 'com.woltlab.wcf.generic'.$pageEditor->pageID
+                       'identifier' => 'com.woltlab.wcf.generic'.$page->pageID
                ]);
                
                if ($this->isLandingPage) {
                        $page->setAsLandingPage();
                }
                
+               // save acl
+               SimpleAclHandler::getInstance()->setValues('com.woltlab.wcf.page', $page->pageID, $_POST);
+               
                // call saved event
                $this->saved();
                
@@ -478,7 +491,8 @@ class PageAddForm extends AbstractForm {
                        'availableApplications' => $this->availableApplications,
                        'availableLanguages' => $this->availableLanguages,
                        'availableBoxes' => $this->availableBoxes,
-                       'pageNodeList' => (new PageNodeTree())->getNodeList()
+                       'pageNodeList' => (new PageNodeTree())->getNodeList(),
+                       'aclValues' => (empty($_POST) ? $this->aclValues : SimpleAclHandler::getInstance()->getOutputValues($this->aclValues))
                ]);
        }
 }
index f6f5497a6349f7ed9c9bd45d78e153c4e84382d5..94511417afa3b62abfbd8bc0d3236b3e62c78f0a 100644 (file)
@@ -3,6 +3,7 @@ namespace wcf\acp\form;
 use wcf\data\page\Page;
 use wcf\data\page\PageAction;
 use wcf\form\AbstractForm;
+use wcf\system\acl\simple\SimpleAclHandler;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\language\LanguageFactory;
 use wcf\system\WCF;
@@ -176,6 +177,9 @@ class PageEditForm extends PageAddForm {
                        $this->page->setAsLandingPage();
                }
                
+               // save acl
+               SimpleAclHandler::getInstance()->setValues('com.woltlab.wcf.page', $this->page->pageID, $this->aclValues);
+               
                // call saved event
                $this->saved();
                
@@ -219,6 +223,8 @@ class PageEditForm extends PageAddForm {
                                        }
                                }
                        }
+                       
+                       $this->aclValues = SimpleAclHandler::getInstance()->getValues('com.woltlab.wcf.page', $this->page->pageID);
                }
        }
        
index 200585f32456380c4b8b61f0a63bbb52da3194c8..5dd0d5dfbace5810a63598b85f54a2e9cc39e23c 100644 (file)
@@ -138,7 +138,7 @@ class UserGroup extends DatabaseObject implements ITitledObject {
         * exists.
         * 
         * @param       integer         $groupID
-        * @return      \wcf\data\user\group\UserGroup
+        * @return      UserGroup|null
         */
        public static function getGroupByID($groupID) {
                self::getCache();
@@ -150,11 +150,27 @@ class UserGroup extends DatabaseObject implements ITitledObject {
                return null;
        }
        
+       /**
+        * Returns a list of groups by group id.
+        * 
+        * @param       integer[]       $groupIDs       list of group ids
+        * @return      UserGroup[]
+        */
+       public static function getGroupsByIDs(array $groupIDs) {
+               $groups = [];
+               foreach ($groupIDs as $groupID) {
+                       $group = self::getGroupByID($groupID);
+                       if ($group !== null) $groups[$groupID] = $group;
+               }
+               
+               return $groups;
+       }
+       
        /**
         * Returns true if the given user is member of the group. If no user is
         * given, the active user is used.
         * 
-        * @param       \wcf\data\user\User     $user
+        * @param       User            $user   user object or current user if null
         * @return      boolean
         */
        public function isMember(User $user = null) {
diff --git a/wcfsetup/install/files/lib/system/acl/simple/SimpleAclHandler.class.php b/wcfsetup/install/files/lib/system/acl/simple/SimpleAclHandler.class.php
new file mode 100644 (file)
index 0000000..16ef728
--- /dev/null
@@ -0,0 +1,218 @@
+<?php
+namespace wcf\system\acl\simple;
+use wcf\data\object\type\ObjectType;
+use wcf\data\object\type\ObjectTypeCache;
+use wcf\data\user\group\UserGroup;
+use wcf\system\cache\runtime\UserRuntimeCache;
+use wcf\system\exception\SystemException;
+use wcf\system\SingletonFactory;
+use wcf\system\WCF;
+use wcf\util\ArrayUtil;
+
+/**
+ * Simplified ACL handlers that stores access data for objects requiring
+ * just a simple yes/no instead of a set of different permissions. 
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Acl\Simple
+ */
+class SimpleAclHandler extends SingletonFactory {
+       /**
+        * list of registered object types
+        * @var ObjectType[]
+        */
+       protected $objectTypes = [];
+       
+       /**
+        * @inheritDoc
+        */
+       protected function init() {
+               $this->objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.acl.simple');
+       }
+       
+       /**
+        * Returns the object type id by object type.
+        * 
+        * @param       string          $objectType     object type name
+        * @return      integer         object type id
+        * @throws      SystemException
+        */
+       public function getObjectTypeID($objectType) {
+               if (!isset($this->objectTypes[$objectType])) {
+                       throw new SystemException("Unknown object type '" . $objectType . "'");
+               }
+               
+               return $this->objectTypes[$objectType]->objectTypeID;
+       }
+       
+       /**
+        * Returns the user and group values for provided object type and object id.
+        * 
+        * @param       string          $objectType     object type name
+        * @param       integer         $objectID       object id
+        * @return      array           array containing the keys `allowAll`, `user` and `group`
+        */
+       public function getValues($objectType, $objectID) {
+               $objectTypeID = $this->getObjectTypeID($objectType);
+               
+               $data = [
+                       'allowAll' => true,
+                       'user' => [],
+                       'group' => []
+               ];
+               
+               $sql = "SELECT  userID
+                       FROM    wcf".WCF_N."_acl_simple_to_user
+                       WHERE   objectTypeID = ?
+                               AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       $objectTypeID,
+                       $objectID
+               ]);
+               $userIDs = [];
+               while ($row = $statement->fetchArray()) {
+                       $userIDs[] = $row['userID'];
+               }
+               
+               $sql = "SELECT  groupID
+                       FROM    wcf".WCF_N."_acl_simple_to_group
+                       WHERE   objectTypeID = ?
+                               AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       $objectTypeID,
+                       $objectID
+               ]);
+               $groupIDs = [];
+               while ($row = $statement->fetchArray()) {
+                       $groupIDs[] = $row['groupID'];
+               }
+               
+               if (!empty($userIDs) || !empty($groupIDs)) {
+                       $data['allowAll'] = false;
+                       
+                       if (!empty($userIDs)) {
+                               $data['user'] = UserRuntimeCache::getInstance()->getObjects($userIDs);
+                       }
+                       
+                       if (!empty($groupIDs)) {
+                               $data['group'] = UserGroup::getGroupsByIDs($groupIDs);
+                       }
+               }
+               
+               return $data;
+       }
+       
+       /**
+        * Sets the user and group values for provided object type and object id.
+        * 
+        * @param       string          $objectType     object type name
+        * @param       integer         $objectID       object id
+        * @param       array           $values         list of user and group ids
+        */
+       public function setValues($objectType, $objectID, array $values) {
+               $objectTypeID = $this->getObjectTypeID($objectType);
+               
+               // validate data of `$values`
+               if (empty($values['user']) && empty($values['group']) && !isset($values['allowAll'])) {
+                       throw new SystemException("Missing ACL configuration values.");
+               }
+               
+               // users
+               $sql = "DELETE FROM     wcf".WCF_N."_acl_simple_to_user
+                       WHERE           objectTypeID = ?
+                                       AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       $objectTypeID,
+                       $objectID
+               ]);
+               
+               if ($values['allowAll'] == 0 && !empty($values['user'])) {
+                       $values['user'] = ArrayUtil::toIntegerArray($values['user']);
+                       if (!empty($values['user'])) {
+                               $sql = "INSERT INTO     wcf" . WCF_N . "_acl_simple_to_user
+                                                       (objectTypeID, objectID, userID)
+                                       VALUES          (?, ?, ?)";
+                               $statement = WCF::getDB()->prepareStatement($sql);
+                               
+                               WCF::getDB()->beginTransaction();
+                               foreach ($values['user'] as $userID) {
+                                       $statement->execute([
+                                               $objectTypeID,
+                                               $objectID,
+                                               $userID
+                                       ]);
+                               }
+                               WCF::getDB()->commitTransaction();
+                       }
+               }
+               
+               // groups
+               $sql = "DELETE FROM     wcf".WCF_N."_acl_simple_to_group
+                       WHERE           objectTypeID = ?
+                                       AND objectID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       $objectTypeID,
+                       $objectID
+               ]);
+               
+               if ($values['allowAll'] == 0 && !empty($values['group'])) {
+                       $values['group'] = ArrayUtil::toIntegerArray($values['group']);
+                       if (!empty($values['group'])) {
+                               $sql = "INSERT INTO     wcf" . WCF_N . "_acl_simple_to_group
+                                               (objectTypeID, objectID, groupID)
+                               VALUES          (?, ?, ?)";
+                               $statement = WCF::getDB()->prepareStatement($sql);
+                               
+                               WCF::getDB()->beginTransaction();
+                               foreach ($values['group'] as $groupID) {
+                                       $statement->execute([
+                                               $objectTypeID,
+                                               $objectID,
+                                               $groupID
+                                       ]);
+                               }
+                               WCF::getDB()->commitTransaction();
+                       }
+               }
+               
+               // reset cache for object type
+               SimpleAclResolver::getInstance()->resetCache($objectType);
+       }
+       
+       /**
+        * Processes the provided values and returns the final
+        * values for template assignment.
+        * 
+        * @param       array   $rawValues      acl values as provided (by the user input)
+        * @return      array   final values for template assignment
+        */
+       public function getOutputValues(array $rawValues) {
+               $aclValues = [
+                       'allowAll' => true,
+                       'user' => [],
+                       'group' => []
+               ];
+               
+               if ($rawValues['allowAll'] == 0) {
+                       if (!empty($rawValues['user'])) {
+                               $aclValues['user'] = UserRuntimeCache::getInstance()->getObjects($rawValues['user']);
+                       }
+                       
+                       if (!empty($rawValues['group'])) {
+                               $aclValues['group'] = UserGroup::getGroupsByIDs($rawValues['group']);
+                       }
+                       
+                       if (!empty($aclValues['user']) || !empty($aclValues['group'])) {
+                               $aclValues['allowAll'] = false;
+                       }
+               }
+               
+               return $aclValues;
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/acl/simple/SimpleAclResolver.class.php b/wcfsetup/install/files/lib/system/acl/simple/SimpleAclResolver.class.php
new file mode 100644 (file)
index 0000000..5e76339
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+namespace wcf\system\acl\simple;
+use wcf\data\user\User;
+use wcf\system\cache\builder\SimpleAclCacheBuilder;
+use wcf\system\SingletonFactory;
+use wcf\system\WCF;
+
+/**
+ * Simplified ACL handlers that stores access data for objects requiring
+ * just a simple yes/no instead of a set of different permissions.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Acl\Simple
+ */
+class SimpleAclResolver extends SingletonFactory {
+       /**
+        * cached permissions per object type
+        * @var array
+        */
+       protected $cache = [];
+       
+       /**
+        * Returns true if there are no ACL settings, the user is allowed or
+        * one of its group is allowed.
+        * 
+        * @param       string          $objectType     object type name
+        * @param       integer         $objectID       object id
+        * @param       User|null       $user           user object, if `null` uses current user
+        * @return      boolean         false if user is not allowed
+        */
+       public function canAccess($objectType, $objectID, User $user = null) {
+               if ($user === null) $user = WCF::getUser();
+               
+               $this->loadCache($objectType);
+               
+               // allow all
+               if (!isset($this->cache[$objectType][$objectID])) {
+                       return true;
+               }
+               
+               if ($user->userID) {
+                       // user is explicitly allowed
+                       if (in_array($user->userID, $this->cache[$objectType][$objectID]['user'])) {
+                               return true;
+                       }
+               }
+               
+               // check for user groups
+               $groupIDs = $user->getGroupIDs();
+               foreach ($groupIDs as $groupID) {
+                       // group is explicitly allowed
+                       if (in_array($groupID, $this->cache[$objectType][$objectID]['group'])) {
+                               return true;
+                       }
+               }
+               
+               return false;
+       }
+       
+       /**
+        * Resets the cache for provided object type.
+        * 
+        * @param       string          $objectType     object type name
+        */
+       public function resetCache($objectType) {
+               SimpleAclCacheBuilder::getInstance()->reset(['objectType' => $objectType]);
+       }
+       
+       /**
+        * Attempts to load the cache for provided object type.
+        * 
+        * @param       string          $objectType     object type name
+        */
+       protected function loadCache($objectType) {
+               if (!isset($this->cache[$objectType])) {
+                       $this->cache[$objectType] = SimpleAclCacheBuilder::getInstance()->getData(['objectType' => $objectType]);
+               }
+       }
+}
diff --git a/wcfsetup/install/files/lib/system/cache/builder/SimpleAclCacheBuilder.class.php b/wcfsetup/install/files/lib/system/cache/builder/SimpleAclCacheBuilder.class.php
new file mode 100644 (file)
index 0000000..bfc501d
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+namespace wcf\system\cache\builder;
+use wcf\system\acl\simple\SimpleAclHandler;
+use wcf\system\WCF;
+
+/**
+ * Caches the simple ACL settings per object type.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    WoltLabSuite\Core\System\Cache\Builder
+ */
+class SimpleAclCacheBuilder extends AbstractCacheBuilder {
+       /**
+        * @inheritDoc
+        */
+       public function rebuild(array $parameters) {
+               $data = [];
+               
+               $objectTypeID = SimpleAclHandler::getInstance()->getObjectTypeID($parameters['objectType']);
+               
+               $sql = "SELECT  objectID, userID
+                       FROM    wcf".WCF_N."_acl_simple_to_user
+                       WHERE   objectTypeID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([$objectTypeID]);
+               while ($row = $statement->fetchArray()) {
+                       $objectID = $row['objectID'];
+                       
+                       if (!isset($data[$objectID])) {
+                               $data[$objectID] = [
+                                       'group' => [],
+                                       'user' => []
+                               ];
+                       }
+                       
+                       $data[$objectID]['user'][] = $row['userID'];
+               }
+               
+               $sql = "SELECT  objectID, groupID
+                       FROM    wcf".WCF_N."_acl_simple_to_group
+                       WHERE   objectTypeID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([$objectTypeID]);
+               while ($row = $statement->fetchArray()) {
+                       $objectID = $row['objectID'];
+                       
+                       if (!isset($data[$objectID])) {
+                               $data[$objectID] = [
+                                       'group' => [],
+                                       'user' => []
+                               ];
+                       }
+                       
+                       $data[$objectID]['group'][] = $row['groupID'];
+               }
+               
+               return $data;
+       }
+}
index 1c7767b88e83b2665179df593d8d7a757e916504..935e91d701104bcda710f5ccf802eec791878145 100644 (file)
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/language.xsd" languagecode="de" languagename="Deutsch" countrycode="de">
        <category name="wcf.acl">
+               <item name="wcf.acl.access"><![CDATA[Zugangsbeschränkung]]></item>
+               <item name="wcf.acl.access.grant"><![CDATA[Zugang gewähren]]></item>
+               <item name="wcf.acl.access.granted"><![CDATA[Erlaubte Benutzer und Benutzergruppen]]></item>
+               <item name="wcf.acl.allowAll"><![CDATA[Inhalt ist für alle Benutzer sichtbar]]></item>
+               
                <item name="wcf.acl.option.deny"><![CDATA[Verweigern]]></item>
                <item name="wcf.acl.option.fullAccess"><![CDATA[Vollzugriff]]></item>
                <item name="wcf.acl.option.grant"><![CDATA[Erlauben]]></item>
index 8f6d0e664964caa27bc672c9d9bf6508b45d60c7..6413cc1d89d1b7648413401805cf3464a339cb2a 100644 (file)
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/language.xsd" languagecode="en" languagename="English" countrycode="gb">
        <category name="wcf.acl">
+               <item name="wcf.acl.access"><![CDATA[Restricted Access]]></item>
+               <item name="wcf.acl.access.grant"><![CDATA[Allow Access]]></item>
+               <item name="wcf.acl.access.granted"><![CDATA[Granted Access for Users and User-Groups]]></item>
+               <item name="wcf.acl.allowAll"><![CDATA[Content Can be Accessed by Everyone]]></item>
+               
                <item name="wcf.acl.option.deny"><![CDATA[Deny]]></item>
                <item name="wcf.acl.option.fullAccess"><![CDATA[Full Access]]></item>
                <item name="wcf.acl.option.grant"><![CDATA[Grant]]></item>
index 7927e2168eb112b657e091c3b4412ef6cef91966..4feb29cbc953392f9c1cace147588ae0775e11ca 100644 (file)
@@ -36,6 +36,22 @@ CREATE TABLE wcf1_acl_option_to_group (
        UNIQUE KEY groupID (groupID, objectID, optionID)
 );
 
+DROP TABLE IF EXISTS wcf1_acl_simple_to_user;
+CREATE TABLE wcf1_acl_simple_to_user (
+       objectTypeID INT(10) NOT NULL,
+       objectID INT(10) NOT NULL,
+       userID INT(10) NOT NULL,
+       UNIQUE KEY userKey (objectTypeID, objectID, userID)
+);
+
+DROP TABLE IF EXISTS wcf1_acl_simple_to_group;
+CREATE TABLE wcf1_acl_simple_to_group (
+       objectTypeID INT(10) NOT NULL,
+       objectID INT(10) NOT NULL,
+       groupID INT(10) NOT NULL,
+       UNIQUE KEY groupKey (objectTypeID, objectID, groupID)
+);
+
 DROP TABLE IF EXISTS wcf1_acp_menu_item;
 CREATE TABLE wcf1_acp_menu_item (
        menuItemID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
@@ -1632,6 +1648,12 @@ ALTER TABLE wcf1_acl_option_to_user ADD FOREIGN KEY (userID) REFERENCES wcf1_use
 ALTER TABLE wcf1_acl_option_to_group ADD FOREIGN KEY (optionID) REFERENCES wcf1_acl_option (optionID) ON DELETE CASCADE;
 ALTER TABLE wcf1_acl_option_to_group ADD FOREIGN KEY (groupID) REFERENCES wcf1_user_group (groupID) ON DELETE CASCADE;
 
+ALTER TABLE wcf1_acl_simple_to_user ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_acl_simple_to_user ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
+
+ALTER TABLE wcf1_acl_simple_to_group ADD FOREIGN KEY (objectTypeID) REFERENCES wcf1_object_type (objectTypeID) ON DELETE CASCADE;
+ALTER TABLE wcf1_acl_simple_to_group ADD FOREIGN KEY (groupID) REFERENCES wcf1_user_group (groupID) ON DELETE CASCADE;
+
 ALTER TABLE wcf1_acp_menu_item ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;
 
 ALTER TABLE wcf1_acp_search_provider ADD FOREIGN KEY (packageID) REFERENCES wcf1_package (packageID) ON DELETE CASCADE;