userXtension

OBSOLETE BY userXtension v2.0

Read in german.

The userXtension is not a common plugin but more like an extension to the dokuwiki platform. The goal is to enable some users to execute special tasks just as in the admin plugins. I want them to manage some features and be seperated from each other.

e.g.: Within my calendar Plugin I’d like the users to administer their own calendar, so that no other user can alter his or her data. In the end the wikis administrator has the possibility to supervise all these calender.

My solution means a little change in the wikis engine:

File /inc/actions.php
In the function act_dispatch() you need to look for if($ACT == ‘admin’){} and enter the following lines below:

	//handle user tasks
	if($ACT == 'user'){
		// retrieve user plugin name from $_REQUEST['page']
		if ($_REQUEST['page']) {
			$pluginlist = plugin_list('user');
			if (in_array($_REQUEST['page'], $pluginlist)) {
				// attempt to load the plugin
				if ($plugin =& plugin_load('user',$_REQUEST['page']) !== NULL)
	        		      $plugin->handle();
			}
		}
	}

This will enable the engine to recognize the call do=user. Alike the admin implementation the call searches for userXtension plugins and prepares them to be executed.

In the function act_clean($act) you have to replace:

	if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
                                             'subscribe','unsubscribe','profile',
                                             'resendpwd',))){

by:

	if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin','user',
                                             'subscribe','unsubscribe','profile',
                                             'resendpwd',))){

This schould cancel every action that comes up if acl is down.

The next bit to replace is:

	if(array_search($act,array('login','logout','register','save','edit',
                             'preview','search','show','check','index','revisions',
                             'diff','recent','backlink','admin','subscribe',
                             'unsubscribe','profile','resendpwd',)) === false

by:

	if(array_search($act,array('login','logout','register','save','edit',
                             'preview','search','show','check','index','revisions',
                             'diff','recent','backlink','admin','user','subscribe',
                             'unsubscribe','profile','resendpwd',)) === false

I think this is checking which actions are available for the wiki at all.

Within the function function act_permcheck($act) look for:

	}elseif($act == 'admin'){
		$permneed = AUTH_ADMIN;

and add the following below:

	}elseif($act == 'user'){
		$permneed = AUTH_CREATE;

This handles the authorization for users of the userXtension. I choose AUTH_CREATE which is the last but one step available. I think it would be usefull to change the authorization system to have an additional AUTH_USER to authorize user calls. I also do think about something that not every user who has the AUTH_USER can alter something in every userXtension ...

The next file is /inc/html.php. replace:

	function html_admin(){

by:

	function html_admin($user=NULL){ // extend call for admin page with user page

replace:

	  print p_locale_xhtml('admin');

by:

	  print p_locale_xhtml($user?'user':'admin'); // call user or admin intro

replace:

	  $pluginlist = plugin_list('admin');

by:

	  $pluginlist = plugin_list($user?'user':'admin'); // get user or admin plugin list

replace:

	    if($obj =& plugin_load('admin',$p) === NULL) continue;

by:

	    if($obj =& plugin_load($user?'user':'admin',$p) === NULL) continue; // load user or admin plugin

replace:

	  if (!$conf['openregister']){

by:

	  if (!$conf['openregister'] && !$user){ // if not open for registering and the call was not from a user, include the 'register new user' part

replace:

	  ptln('  <li><div class="li"><a href="'.wl($ID, 'do=admin&amp;page='.$item['plugin']).'">'.$item['prompt'].'</a></div></li>');

by:

	  ptln('  <li><div class="li"><a href="'.wl($ID, 'do=' . ($user?'user':'admin') .  '&amp;page='.$item['plugin']).'">'.$item['prompt'].'</a></div></li>'); // create link to plugin with the discision to load the user or admin part

These where all the changes within the system files. The last thing is to create a file user.php in the plugin directory alike the admin.php. This will be the prototype for the user plugins.

/lib/plugins/user.php

<?php
/**
 * User Plugin Prototype
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Christopher Smith <chris@jalakai.co.uk>
 * @author     Gerry Weissbach <gerry.w@gammaproduction.de>
 */
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');

/**
 * All DokuWiki plugins to extend the user function
 * need to inherit from this class
 */
class DokuWiki_User_Plugin {

  var $localised = false;        // set to true by setupLocale() after loading language dependent strings
  var $lang = array();           // array to hold language dependent strings, best accessed via ->getLang()

  /**
   * General Info
   *
   * Needs to return a associative array with the following values:
   *
   * author - Author of the plugin
   * email  - Email address to contact the author
   * date   - Last modified date of the plugin in YYYY-MM-DD format
   * name   - Name of the plugin
   * desc   - Short description of the plugin (Text only)
   * url    - Website with more information on the plugin (eg. syntax description)
   */
  function getInfo(){
    trigger_error('getInfo() not implemented in '.get_class($this), E_USER_WARNING);
  }

  function getMenuText($language) {
      $menutext = $this->getLang('menu');
      if (!$menutext) {
        $info = $this->getInfo();
        $menutext = $info['name'].' ...';
      }
      return $menutext;
  }

  function getMenuSort() {
    return 1000;
  }

  function handle() {
    trigger_error('handle() not implemented in '.get_class($this), E_USER_WARNING); 
  }

  function html() {
    trigger_error('html() not implemented in '.get_class($this), E_USER_WARNING); 
  }
  
  // private methods (maybe a dokuwiki plugin base class is required for these)
  
  // plugin introspection methods
  // extract from class name, format = <plugin type>_plugin_<name>[_<component name>]
  function getPluginType() { list($t) = explode('_', get_class($this), 2); return $t;  }

  function getPluginName() { list($t, $p, $n) = explode('_', get_class($this), 4); return $n; }
  function getPluginComponent() { list($t, $p, $n, $c) = explode('_', get_class($this), 4); return (isset($c)?$c:''); }

  // localisation methods
  /**
   * getLang($id)
   * use this function to access plugin language strings
   * to try to minimise unnecessary loading of the strings when the plugin doesn't require them
   * e.g. when info plugin is querying plugins for information about themselves.
   *
   * @param   $id     id of the string to be retrieved
   * @return  string  string in appropriate language or english if not available
   */
  function getLang($id) {
    if (!$this->localised) $this->setupLocale();
    
    return (isset($this->lang[$id]) ? $this->lang[$id] : '');
  }
  
  /**
   * locale_xhtml($id)
   *
   * retrieve a language dependent file and pass to xhtml renderer for display
   * plugin equivalent of p_locale_xhtml()
   *
   * @param   $id     id of language dependent wiki page
   * @return  string  parsed contents of the wiki page in xhtml format
   */
  function locale_xhtml($id) {
    return p_cached_xhtml($this->localFN($id));
  }
  
  /**
   * localFN($id)
   * prepends appropriate path for a language dependent filename
   * plugin equivalent of localFN()
   */
  function localFN($id) {
    global $conf;
    $plugin = $this->getPluginName();
    $file = DOKU_PLUGIN.$plugin.'/lang/'.$conf['lang'].'/'.$id.'.txt';
    if(!@file_exists($file)){
      //fall back to english
      $file = DOKU_PLUGIN.$plugin.'/lang/en/'.$id.'.txt';
    }
    return $file;
  }
  
  /**
   *  setupLocale() 
   *  reads all the plugins language dependent strings into $this->lang
   *  this function is automatically called by getLang()
   */
  function setupLocale() {
    if ($this->localised) return;

    global $conf;            // definitely don't invoke "global $lang"
    $path = DOKU_PLUGIN.$this->getPluginName().'/lang/';

    $lang = array();
 
    // don't include once, in case several plugin components require the same language file
    @include($path.'en/lang.php');    
    if ($conf['lang'] != 'en') @include($path.$conf['lang'].'/lang.php');
    
    $this->lang = $lang;
    $this->localised = true;
  }
  
  // standard functions for outputing email addresses and links
  // use these to avoid having to duplicate code to produce links in line with the installation configuration
  function email($email, $name='', $class='', $more='') {
    if (!$email) return $name;
    $email = obfuscate($email);
    if (!$name) $name = $email;
    $class = "class='".($class ? $class : 'mail')."'";
    return "<a href='mailto:$email' $class title='$email' $more>$name</a>";
  }
  
  function external_link($link, $title='', $class='', $target='', $more='') {
    global $conf;
    
    $link = htmlentities($link);
    if (!$title) $title = $link;
    if (!$target) $target = $conf['target']['extern'];
    if ($conf['relnofollow']) $more .= ' rel="nofollow"';
    
    if ($class) $class = " class='$class'";
    if ($target) $target = " target='$target'";
    if ($more) $more = " ".trim($more);
                
    return "<a href='$link'$class$target$more>$title</a>";
  }
                
  // output text string through the parser, allows dokuwiki markup to be used
  // very ineffecient for small pieces of data - try not to use
  function render($text, $format='xhtml') {
    return p_render($format, p_get_instructions($text),$info); 
  }
  
  // deprecated functions
  function plugin_localFN($id) { return $this->localFN($id); }
  function plugin_locale_xhtml($id) { return $this->locale_xhtml($id); }
  function plugin_email($e, $n='', $c='', $m='') { return $this->email($e, $n, $c, $m); }
  function plugin_link($l, $t='', $c='', $to='', $m='') { return $this->external_link($l, $t, $c, $to, $m); }
  function plugin_render($t, $f='xhtml') { return $this->render($t, $f); }
  
}
//Setup VIM: ex: et ts=4 enc=utf-8 :

To create a user plugin you do the same steps as for the admin plugins: Create a user.php. the inner structure is the same as in admin.php.

If there are any questions or suggestions mail me at: gerry.w@gammaproduction.de