Table of Contents

Disable Actions by Group

This plugin allows you to disable a given list of actions based on user groups. It has been tested to work with the latest release of DokuWiki (2006-11-06). There are two configuration settings:

Download/Install

To install the plugin either use the plugin manager or extract this zip file into your plugins directory:

Example


FIXME updated screenshot with new ignore_admin setting In this example (note: uses the patch to allow restricting ALL published below), the following groups have been prohibited the following actions:

List of valid actions

By default, these actions come with dokuwiki. More can be added through the use of plugins:

Discussion

Little patch to allow removing rights from the ALL (anonymous users) group as well as making ADMIN ignore the plugin (needed if you want to restrict a right from 'user' or other groups but still allow admin to perform it.

lines 38++

	function _hookaction() {
		global $INFO, $ACT;
 
		$info = $INFO['userinfo']['grps'];
		//if not logged in, don't do anything
		if(!is_array($info)){
			$info = array("ALL");
		//	return;
		}
		else /* comment this out if you don't want admin to ignore all settings by the plugin */ 
		{
			if ($INFO['perm'] >= AUTH_ADMIN)
			{
				return;
			}
		}
///...

and lines 73++

	//first check to see if this user has actions disabled
	$disabled = array();
	$intersect = array_intersect($groups, $info);
 

makes it more useful, e.g. to allow logged in users but not guests to see recent changes. — Georg Zoeller 2007-01-03 04:18

FIXME When disabling an action in admin interface in a common way, the corresponding button disappears from the page. It's not the case with this plugin. Isn't it better to do the same thing rather than allow guests hitting buttons that don't do anything? Best regards!


Would this (slightly modified) end of the file work? Seems to work for me, on a quick try.

	/*
	 * Register its handlers with the dokuwiki's event controller
	 */
	function register(&$controller) {
		$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE',  $this, '_hookaction');
		$controller->register_hook('ACTION_ACT_PREPROCESS', 'AFTER',  $this, '_hookaction_login');
	}
 
        /* Temporary store for disabled actions in case login privileges change */
        private $olddisableactions;
 
	/*
	 * Check to see if they are just loggin in and redirect to start page, or if page doesn't exist and they are logged in and the group is set to redirect to start go to start page
	 */
	function _hookaction() {
		global $INFO, $ACT, $conf;
 
		$this->olddisableactions = $conf['disableactions'];
 
		$info = $INFO['userinfo']['grps'];
		//if not logged in, don't do anything
		if(!is_array($info))
			$info = array("ALL");
		elseif($this->getConf('ignore_admin')==1 && $INFO['perm'] >= AUTH_ADMIN)
			return;
 
		//if no groups defined, do nothing
		if($this->getConf('group_list') == '')
			return;
 
		$groups = explode(';', $this->getConf('group_list'));
		if($this->getConf('action_list') == '') $actions = array();
		else $actions = explode(';', $this->getConf('action_list'));
 
		//sanitize the settings
		if(sizeof($actions) != sizeof($groups)) {
			if(sizeof($groups) < sizeof($actions))
				$groups = array_splice($groups, sizeof($actions));
			else
				$actions = array_pad($actions, sizeof($groups), "");
 
			trigger_error("Plugin disableactionsbygroup: Number of groups defined doesn't match actions count.", E_USER_WARNING);
		}
 
		//first check to see if this user has actions disabled
		$disabled = explode(',', $conf['disableactions']);
		$intersect = array_intersect($groups, $info);
		foreach($intersect as $k => $v) {
			if($actions[$k] != '')
				$disabled = array_merge($disabled, explode(',', $actions[$k]));
		}
		$disabled = array_unique($disabled);
		if(!sizeof($disabled))
			return;
		if(sizeof($disabled) == 1)
			if($disabled[0] == '')
				return;
 
		$conf['disableactions'] = join(',', $disabled);
	}
 
	/*
	 * If login privileges have changed, reconstruct disabled actions
	 */
	function _hookaction_login() {
		global $ACT, $conf;
 
		//login stuff
    		if(in_array($ACT,array('login','logout'))) {
			$conf['disableactions'] = $this->olddisableactions;
			$this->_hookaction();
		}
	}

FIXME To make this work properly on logout (show correct buttons without reloading), function actionOK must be modified in inc/confutils.php. The replacement below makes it slightly less efficient, but fixes actionOK results (and resulting buttons/actions) when value of $conf['disableactions'] changes between invocations of the function:

function actionOK($action){
  global $conf;
  static $olddisableactions = null;
  static $disabled = null;
 
  if($olddisableactions !== $conf['disableactions']){
    // prepare disabled actions array and handle legacy options
    $disabled = explode(',',$conf['disableactions']);
    $disabled = array_map('trim',$disabled);
    if(isset($conf['openregister']) && !$conf['openregister']) $disabled[] = 'register';
    if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) $disabled[] = 'resendpwd';
    $disabled = array_unique($disabled);
    $olddisableactions = $conf['disableactions'];
  }
 
  return !in_array($action,$disabled);
}

Jari Kirma 2007-09-25 09:22

I had a couple of issues with the plugin as it exists from source on this page.

  1. The last modification re: the ALL group is a bit problematic because the definition of ALL (anyonymous users) from Georg's patch doesn't agree with the DokuWiki definition of ALL which includes ALL users, both logged in, and not logged in.
  2. I am not sure that I agree with the implementation of the ignore_admin option since I can't think of any reason why the admin of the site should ever be denied access to anything. At least that's the way DokuWiki ACLs work. The admin always has access to everything.
  3. In my opinion, if you have a user X who is in groups A and B, and the admin has disabled action Z for group A, then user X should not be disallowed access to action Z because user X is in group B where no actions have been disabled. As far as I can tell this is not the way the current plugin works. Currently, user X would be denied because he is in group A.

I have created the patch below which does the following:

  1. fix the definition of ALL (users are ALWAYS in the ALL group)
  2. get rid of ignore_admin
  3. fix group checking as per 3 above (note: if you remove access to ALL for say, “revisions”, and you really wish to remove access to “revisions” for all of your users, then you are going to need to add another restriction for your users group because omitting this restriction would then provide your users with access to “revisions”.)

Finally, while I agree that it would be nice if this plugin disabled the actions from being displayed through templates, I'm not overly fond of the idea of modifying the actual DokuWiki code to fix the problem because these types of patches need to be reapplied to every DokuWiki version. On the other hand, if this plugin implemented a check function that a template could call when printing the buttons (kind of like actionOK), this might not be a bad idea because the templates don't always change with DokuWiki versions. However, this would tie the template to this plugin…

Regarding the above actionOK replacement: everything works correctly without it, except when user logs out, the page loaded after logout is constructed with privileges of user that logged out (the actions represented by extra buttons don't work, though). So, it's really rather cosmetic change, but it's good to note that current standard implementation caches $disabled after first invocation of actionOK in a way that can be detrimental.
Jari Kirma 2007-09-26 14:24

Here's my patch in patch format:

diff -Naur disableactionsbygroup.orig/action.php disableactionsbygroup/action.php
--- disableactionsbygroup.orig/action.php	2007-02-21 07:03:17.000000000 -0500
+++ disableactionsbygroup/action.php	2007-09-25 13:12:32.000000000 -0400
@@ -33,34 +33,37 @@
 	}

 	

 	/*

-	 * Check to see if they are just loggin in and redirect to start page, or if page doesn't exist and they are logged in and the group is set to redirect to start go to start page
-	 */
-	function _hookaction() {
-		global $INFO, $ACT;
-
-		$info = $INFO['userinfo']['grps'];
-		//if not logged in, don't do anything
-		if(!is_array($info)) {
-			$info = array("ALL");
-		}
-		elseif($this->getConf('ignore_admin')==1 && $INFO['perm'] >= AUTH_ADMIN) {
-			return;
-		}
-		
-		//if no action, do nothing
-		if(!$ACT) {
-			return;
-		}
-		
+	 * Check to see if they are just loggin in and redirect to start page, or if page doesn't exist and they are logged in and the group is set to redirect to start go to start page

+	 */

+	function _hookaction() {

+		global $INFO, $ACT;

+

+		$info = $INFO['userinfo']['grps'];

+		//if user not in any explicit groups, they are in ALL group

+		if(!is_array($info)) {

+			$info = array("ALL");

+		} else {

+ 			// add ALL group to user

+                	$info[] = "ALL";

+              		// admin is not denied access to anything

+                        if($INFO['perm'] >= AUTH_ADMIN) 

+				return;

+                }

+

+		//if no action, do nothing

+		if(!$ACT) {

+			return;

+		}

+

 		//if no groups defined, do nothing

 		if($this->getConf('group_list') == '') {

 			return;

 		}

-		

+

 		$groups = split(';', $this->getConf('group_list'));

 		if($this->getConf('action_list') == '') $actions = array();

 		else $actions = split(';', $this->getConf('action_list'));

-		

+

 		//sanitize the settings

 		if(sizeof($actions) != sizeof($groups)) {

 			if(sizeof($groups) < sizeof($actions))

@@ -71,15 +74,30 @@
 			trigger_error("Plugin disableactionsbygroup: Number of groups defined doesn't match actions count.", E_USER_WARNING);

 		}

 

-		//first check to see if this user has actions disabled

 		$disabled = array();

+

+                // if user is in at least 1 group that does not have any

+                // restrictions, access is permitted

+                if (count(array_diff($info,$groups)) > 0) 

+			return;

+

+                // create a list of actions that are disabled for this user

 		$intersect = array_intersect($groups, $info);

 		foreach($intersect as $k => $v) {

-			if($actions[$k] != '') {

-				$disabled = array_merge($disabled, split(',', $actions[$k]));

-			}

+ 			// if action list is empty for any denied group

+			// that the user is in, its the same thing as if 

+ 			// there are no restrictions on the group, and hence

+			// access is permitted

+   			if($actions[$k] == '')

+				return;

+			// otherwise, an action is only disabled for a user

+			// if it is disabled in all groups that the user is

+			// in

+                        if (empty($disabled)) 

+                          $disabled = split(',', $actions[$k]);

+                        else

+			  $disabled = array_intersect($disabled, split(',', $actions[$k]));

 		}

-		$disabled = array_unique($disabled);

 		if(!sizeof($disabled))

 			return;

 		if(sizeof($disabled) == 1)

@@ -91,7 +109,7 @@
 			return;

 

 		//so now we know that this action is disabled, so show an error page or something...

-		msg('Command disabled: '.htmlspecialchars($ACT),-1);

+		msg('The administrator has disabled access to: '.htmlspecialchars($ACT),-1);

 		$ACT = 'show';

 	}

 }

(Note: you must also remove the “ignore_admin” from conf/default.php conf/metadata.php, and lang/en/settings.php)

Jason Keltz 2007-09-25 13:36