User:anbrcyp > Page Restriction Modification

Page Restriction Modification

Overview

The attached php files contain code changes that extends the permission granularity of 'Public' pages to 'Semi-public' and 'Private' pages.  These files are being posted for those who want to test out the concept of a wiki capable of more flexible restrictions.  Hopefully, it will help determine what could be changed in the current UI to make a complex restriction UI easy and/or intuitive to work with.

These files do not create or use functions, features, or methods that were not already available through the Deki API.  The only significant change is that a grant's role will be saved according to the role associated with a user or group instead of being set to a default value ($wgDefaultRestrictRole).  I've tested it on my dev box, believe it is running without major issues, and that using it will not damage the wiki.

Disclaimer:  This code is functional and safe to the best of my knowledge, however, it is not an official modification and you are ultimately responsible for dealing with the result of any changes to your wiki.  This code was written for experimental purposes, and I do not recommend it for a 'live' wiki.

   

Example Case

Simple example case that demonstrates the new functionality (hopefully, it makes sense):

 Group info:

Group Role Members
Group1 Viewer User1, User2
Group2 Contributor User2

 Case 1: Private page, grant list = Group1

User Role
User1 Viewer
User2 Viewer

 Case 2: Private page, grant list = Group1, Group2

User Role
User1 Viewer
User2 Contributor

   

Setup

8.05.2b:

Simply extract the php files to your '<deki>/web/includes' directory.  You may want to rename the original files before hand:

  • GlobalFunctions.php
  • AdminGroups.php
  • AdminUsers.php

Change notes:

The original version used DreamUserManagement.php and DreamGroupManagement.php to call wfResetRestrictions.  However, that approach resulted in the grants being rewritten for every single group or user update.  I moved the call to AdminGroups.php and AdminUsers.php so that the wiki is only updated once.  This was neccessary mostly because of the poor speed design of wfResetRestrictions.  Sorry, but I still haven't made an attempt to increase the reset's overall speed yet.  The original version of wfResetRestrictions would post a 'Permissions updated' for every page that was touched.  The new version is modified to only report a single time once the update is finished.

8.08:

The method has been redesigned slightly.  The main difference is that triggering a full grant reset is manually done on the Authentication sub-page of deki-cp.

Extract the following files to your wiki directory.  Renaming/archiving the original files is recommended:

  • <root_dir>/web/includes/GlobalFunctions.php
  • <root_dir>/web/deki-cp/authentication.php
  • <root_dir>/web/deki-cp/templates/authentication/listing.php
  • <root_dir>/web/resources/resources.custom.txt  *if you already have an existing custom file, just append the contents of this one

Change notes:

This version puts grant resets in the hands of the admin now.  Simply navigate to the Authentication page of the control panel, and there should be a sub-section that triggers a grant reset.  All of the logic for the reset is contained in the updated authentication.php file.  I attempted to minimize the amount of API calls to improve speed (it gathers all of the needed data using MySQL).  Unfortunately, it turns out that most of the time sink is within the API call to update the page grants.  Pages which require a grant update take an average of about 10 times longer to process than ones which don't (each API call ranged from ~40ms to over 200ms on my dev PC).  Fortunately, if a page requires no updates, the API call only takes a few ms (ranged from 4ms to 8ms for me).

 

Usage

Grant information, including the role value of each grant, is stored as part of each page's data.  This allows for very complex and varied permissions throughout the wiki.  Until the new code is executed, all existing grants in your wiki will have the default value assigned by the normal method.  The modified code looks up the role associated with each user or group that is being given a grant and saves that specific role; the default variable is not used at all.

There are only two events that will trigger the new code:

  • Update a page's grants: each page's grants must be explicitly updated in order to work with the new, correct role values.  Select More->Restrict access and use the restriction dialogue like normal.  When your changes are saved, each group/user grant will be set to its correct role value.
  • Trigger a site wide grant reset: because all pages retain their grant information independent from the rest of the wiki, grants will be incorrect whenever a user or group role is changed.  To deal with this issue, both version have a grant reset function which iterates through pages in the wiki and rewrites the grant data.  This function is called automatically every time a user or group is updated in 8.05.2b, and is called manually from the Authentication control panel page in 8.08.

Triggering a grant reset is the way to push a grant update to many pages automatically.  The 8.05.2b code only touches pages off the main branch, but the 8.08 version touches the grants of any currently existing page with restriction data (deleted pages will not be updated).  It is much quicker than opening and saving each set of page grants manually.  Unfortunately, this function is a very ugly, brute force answer to the issue of getting the wiki grants updated.  It may take a significant amount of time for large wikis.  My test setup took about 30 seconds for 300 pages and 3+ grants per page in 8.08 with every page being updated.  It runs considerably quicker if a page doesn't need to be updated, taking about 3 seconds if all 300 pages are up to date.

Note: the performance hit is primarily due to MySQL settings.  Setting MySQL to use log file caching will improve the time for the grant reset and many other database commits... however, it kills ACID compliance and isn't recommended for sites with critical data.

# If set to 1, InnoDB will flush (fsync) the transaction logs to the
# disk at each commit, which offers full ACID behavior. If you are
# willing to compromise this safety, and you are running small
# transactions, you may set this to 0 or 2 to reduce disk I/O to the
# logs. Value 0 means that the log is only written to the log file and
# the log file flushed to disk approximately once per second. Value 2
# means the log is written to the log file at each commit, but the log
# file is only flushed to disk approximately once per second.
innodb_flush_log_at_trx_commit=1

   

Undoing the Mod

It is possible to use the modified code to undo the grant changes to your wiki.  Returning your wiki to a state of default grant roles requires editing the new php code.  The original role assignment code is still present, but simply commented out.  Follow these steps to return the wiki to a normal state:

8.05.2b:

  1. Change the commenting in GlobalFunctions.php:
    • Go to around 1580 and 1650 in GlobalFunctions.php.  You should find blocks of code that look like the code displayed below.
      $grants = array();
      $groups = array_unique($groups);
      $users = array_unique($users);
      
      //foreach ($users as $userId) 
      //{
      //	$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => $userId));
      //}
      //foreach ($groups as $groupId) 
      //{
      //	$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => $groupId));
      //}
      
      foreach ($users as $userId) 
      {
      	$role = new DreamUserManagement();
      	$grants[] = array('permissions' => array('role' => $role->getById($userId)->GetRole()->GetName()), 'user' => array('@id' => $userId));
      }
      foreach ($groups as $groupId) 
      {
      	$role = new DreamGroupManagement();
      	$grants[] = array('permissions' => array('role' => $role->getById($groupId)->GetRole()->GetName()), 'group' => array('@id' => $groupId));
      }
    • Change the comment notation (//): remove at lines 5-12, and add at lines 14-23.
    • The 'fixed' code blocks should look like this.
      $grants = array();
      $groups = array_unique($groups);
      $users = array_unique($users);
      
      foreach ($users as $userId) 
      {
      	$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => $userId));
      }
      foreach ($groups as $groupId) 
      {
      	$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => $groupId));
      }
      
      //foreach ($users as $userId) 
      //{
      //	$role = new DreamUserManagement();
      //	$grants[] = array('permissions' => array('role' => $role->getById($userId)->GetRole()->GetName()), 'user' => array('@id' => $userId));
      //}
      //foreach ($groups as $groupId) 
      //{
      //	$role = new DreamGroupManagement();
      //	$grants[] = array('permissions' => array('role' => $role->getById($groupId)->GetRole()->GetName()), 'group' => array('@id' => $groupId));
      //}
  2. Trigger wfResetRestrictions or manually update restrictions by using More->Restrict access.
  3. Restore original versions of the php files once the grants have returned to normal.

8.08:

  1. Change the commenting in GlobalFunctions.php and authentication.php:
    1. In GlobalFunctions.php, find the following code block (starts at line 1584) and swap the line commenting:
      //foreach ($users as $userId)
          //{
          //    $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => $userId));
          //}
          //foreach ($groups as $groupId)
          //{
          //    $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => $groupId));
          //}
      
          foreach ($users as $userId)
          {
              $role = new DreamUserManagement();
              $grants[] = array('permissions' => array('role' => $role->getById($userId)->GetRole()->GetName()), 'user' => array('@id' => $userId));
          }
          foreach ($groups as $groupId)
          {
              $role = new DreamGroupManagement();
              $grants[] = array('permissions' => array('role' => $role->getById($groupId)->GetRole()->GetName()), 'group' => array('@id' => $groupId));
          }
    2. The fixed GlobalFunction.php should look like this:
      foreach ($users as $userId)
          {
              $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => $userId));
          }
          foreach ($groups as $groupId)
          {
              $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => $groupId));
          }
      
          //foreach ($users as $userId)
          //{
          //    $role = new DreamUserManagement();
          //    $grants[] = array('permissions' => array('role' => $role->getById($userId)->GetRole()->GetName()), 'user' => array('@id' => $userId));
          //}
          //foreach ($groups as $groupId)
          //{
          //    $role = new DreamGroupManagement();
          //    $grants[] = array('permissions' => array('role' => $role->getById($groupId)->GetRole()->GetName()), 'group' => array('@id' => $groupId));
          //}
    3. In authentication.php, find the following code block (starts at line 692) and swap the the commenting on the $grant[] assignments:
      foreach ($pages[$pid]['grants'] as $grant)
          {
              if (strncmp($grant, 'g', 1) == 0)
              {
                  $grants[] = array('permissions' => array('role' => $group_roles[substr($grant, 1)]), 'group' => array('@id' => substr($grant, 1)));
                  //$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => substr($grant, 1)));
              }
              else
              {
                  $grants[] = array('permissions' => array('role' => $user_roles[substr($grant, 1)]), 'user' => array('@id' => substr($grant, 1)));
                  //$grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => substr($grant, 1)));
              }
          }
    4. The fixed authentication.php should look like this:
      foreach ($pages[$pid]['grants'] as $grant)
          {
              if (strncmp($grant, 'g', 1) == 0)
              {
                  //$grants[] = array('permissions' => array('role' => $group_roles[substr($grant, 1)]), 'group' => array('@id' => substr($grant, 1)));
                  $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'group' => array('@id' => substr($grant, 1)));
              }
              else
              {
                  //$grants[] = array('permissions' => array('role' => $user_roles[substr($grant, 1)]), 'user' => array('@id' => substr($grant, 1)));
                  $grants[] = array('permissions' => array('role' => $wgDefaultRestrictRole), 'user' => array('@id' => substr($grant, 1)));
              }
          }
  2. Trigger a grant reset from the Authentication page in the new control panel, or manually reset grants by using More->Restrict access.
  3. Restore original versions of the php files once the grants have returned to normal.

 

Giving Feedback

I'm not one of the people responsible for final development and approval of the Deki software.  However, I am one of the people who would like to see an improved version of the existing restriction model.  The current permission system is up for redesign in the Lyons release. Please share any ideas for improvements on this page.

If you have any questions or problems specifically about this mod, send me a PM and I'll do my best to help.

Tag page

Files 2

FileSizeDateAttached by 
restrict_mod.zip
Restriction Modifications - 8.05.2b Base
36.56 kB16:05, 15 Aug 2008anbrcypActions
 restrict_mod_8_08.zip
Mod for 8.08; redesign to trigger from deki-cp.
27.21 kB00:25, 9 Oct 2008anbrcypActions
Viewing 9 of 9 comments: view all
Wow, great modification. I hope we can one day take some iteration of it into the main product (after Kilen Woods, let's hope!)
Posted 20:30, 13 Aug 2008
Cool, and thank you. It'd be great to see something similar to this, but polished. Hopefully this'll make it a little easier for initial 'concept' testing.
Posted 07:51, 14 Aug 2008
Cleaned up the page a little bit. Hurt my eyes to read it after I got some sleep.
Posted 16:10, 15 Aug 2008
Thank you very much for that GREAT modification! It works like a charm!
Posted 10:48, 21 Aug 2008
You're welcome, Doc. And sorry about the speed issues when changing a user or group role. I just haven't been able to come up with any way to update sitewide roles quickly and correctly without using MySQL directly.
Posted 12:07, 2 Sep 2008
Hi Andrew - works fine, now the "restrict access" works exactly as it should (the speed issue when changing roles is an admin-only "problem"). I hope that this mod will be part of the official releases as soon as possible. Thank You!
Posted 13:28, 3 Sep 2008
Thank you for the mod for 8.08 - it works well on the test system and we will update and patch the live system today.
Well, I have read your disclaimer - but this functionality is quite essential for us and the first version of the patch still works fine.
Posted 09:38, 13 Oct 2008
Yes, there wasn't actually any change in the set page restriction code for 8.08 and 8.05.2b. GlobalFunctions.php from either patch should work on a single page without a problem. The only major difference between the two is the way site wide grants are reset. Apologies if the method change causes any problems, but I wanted to use deki-cp, keep the file count to a minimum, and try to speed it up. I ended up dropping the old admin method completely, even though it still technically works.
Posted 08:01, 14 Oct 2008
Hello Andrew - I am quite happy with your patch, but it has at least one impact that should be mentioned: Everytime an admin does the "grant reset", every page in the wiki which has inherited permissions gets a reset to exactly that set of permissions - additional or revoked permissions will be deleted.
We circumvent this issue with simply not using the "grant reset" function - this is fine as long as the roles of users and groups are not modified (this is no problem for us).
Posted 13:49, 18 Dec 2008
Viewing 9 of 9 comments: view all
You must login to post a comment.
Powered by MindTouch Deki v.8.08.2