DokuWiki

It's better when it's simple

User Tools

Site Tools


tips:homepages

This is an old revision of the document!


How to create user homepages

Author: Oliver Geisen
Overview: Create homepages for dokuwiki-users without the need of complex ACLs
Based on: dokuwiki-2006-03-09
Plugins needed: none

:!: Please note: This TIP is a simple hack. It would even be better to think all over and find a better solution to provide homepages for users, especially the way to authorize the namespaces they are in. Maybe a variable like %USERID% could be used in ACL.

update: just use %USER% in your acl.auth.php, it will be subsituted by the current logged in user, and include tpl_link(wl(“user:”.$INFO[userinfo][name],'do=show'),“My homepage”); to your template.

Motivation

We (dokuwiki admins) want to give our dokuwiki-users the ability to create their own homepages. These should be in their own responsibility and therefore in their own namespace. The user may create as many pages as he want inside this namespace (Think twice: “should'nt there be some kind of quota ?”). Each user created with the usermanager should be provided with a namespace dedicated to him and a simple starting template. Also there should be a “My page” button in the navigation bar, so users can easily access their pages.

How is it all done ?

Each page the user see's is requested from the browser like:

http://<server>/doku.php?id=<wiki-path>

doku.php itself will initialize some environment, sets global variables, checks ACLs and will then call main.php from the currently selected template, which is found at:

lib/tpl/<template>/main.php

So we must decide where to hack the code: Inside ACL checking or where page is shown. I decided to do all the work needed just before the page is shown because I want to keep ACLs clean and simple. Therefore we must make some decicions now:

  1. Where should the homepage namespace be ?
  2. Should other users have access (mostly read-only) to homepages ?

I decide to:

  • start my user namespace at: home: (just like unix do)
  • keep users pages private. In order to edit the pages add
    home:*  @ALL    0
    home:*  @user   16

    to conf/acl.auth.php.

Extend ACL if user requests his own homepage-namespace

The next challenge was to find the place in code where user should be given full access to his namespace. We've discovered that main.php is called at least, so let's look inside and we found a call like:

<?php tpl_content()?>

Let's do a simple grep-search inside the dokuwiki base-directory to find the lib which exports this function:

grep -r "function tpl_content" *

The answer is: inc/template.php. So lets look inside the function and determine how it works. It imports some globals, where $ID contains the wiki-url to the page requested and $ACT the thing to do (mostly “show”).

So this leads us to “html_show()”, which we can find, using grep-search like before, inside “inc/html.php”. Further look show that it simply displays/renders the wiki-source-text, so this is too deep to implement the code needed. I decide to put in into “tpl_content()” right after the global definitions:

  ... global imports ...
 
  // if $ID (requested page) starts with 'home:' and we are not the "admin" do some extra checking
  if((substr($ID,0,5) == 'home:') && ($INFO['perm'] != AUTH_ADMIN)){
    $userid = $_SESSION[$conf['title']]['auth']['user'];
    $allowed = 'home:'.$userid.':';
    // if user requests the page of another users homedir, deny access to it
    if(substr($ID,0,strlen($allowed)) != $allowed){
      print p_locale_xhtml('denied');
      return;
    }
  }
  // only admins, users requesting pages from their own homespace, or users requesting other namespaces will get here
 
  ... regular code continues ...

Add "My page" button to navigation bar

Add the code to display the new button inside main.php of the template:

  <?php tpl_button('mypage') ?>

Now let's find out where tpl_button comes from. Just use grep-search again and see it's inside inc/template.php (haha, surprise surpise, who had thought that all functions prefixed with “tpl_” comes from template.php ;-)))

Ok, i just added a new case-statement for my button:

  ...
  case 'mypage':
    $uid = $_SESSION[$conf['title']]['auth']['user'];
    $id = 'home:'.$uid.':index';
    print html_btn('mypage',$id,'u',array("do" => "show"));
    break;
  ...

Next, we need to add the button-label for “mypage”. A quick look inside “html_btn” (which is found in inc/html.php) shows that each label is prefixed with “btn_”, which results in “btn_mypage” in our case, and is looked up in the language-file. This is found at:

inc/lang/<language>/lang.php

Here i append a new line containing:

$lang['btn_mypage']     = 'Meine Seite';

Please note “Meine Seite” is German. Just put whatever YOU want, of course ;-)

Now you can try it, and find a good place for the button inside main.php.

Autocreate homespace for users

Because users are not able to create own namespace in “home:” we must provide them one. Best place to do this is when adding the user with the usermanager. The usermanager is a default plugin of dokuwiki and it's code is found at:

lib/plugins/usermanager/

Next we must find the place where the new user is created to add our code to create the homespace as well. In the “handle()” function we found a case-switch with a case “add” : $this→_addUser(); break; - this is our man!

So lets follow the call to the function “_addUser()”. It first gets data from the POSTed form, which normally contains the params of the new user to be created (name, mail, password, etc.). Next it wraps to $this→_auth→createUser($user,$pass,$name,$mail,$grps);. This function is not contained here, because “_auth” is another object which will be dynamically set by the choosen authentication method.

I use “plaintext” authentication so i found out that inc/auth/plaintext.php is the place to search for “createUser”. All this function do is to add the credentials given to the “user database” and returns “false” if the user already exists, “null” when an error has occured and “true” if everything went well.

Because our solution should not depend upon the selected authentication method, it's best to add it to the usermanager code. The problem here is how to build up the path to the namespace for the user to create with mkdir (or better io_mkdir_p() from inc/io.php).

So lets start thinking reverse again. What happens if one clicks on “Create page”? Yes, a page opens with an empty editfield and a “Save” button under it. This buttons is worth a closer look, so check HTML-source and found out that it will call doku.php with “do=save” and “id=<pageid>”. Now i go all the way through doku.php down until inc/actions.php where “save” is handled and came up to the function “act_save($ACT)”. After a few checks it will call “saveWikiText(…)” which i found in inc/common.php.

Here i found two very interesting things:

  1. the call to “wikiFN($id)” which in result gives us the full path into the local filesystem, where page $id is/should be stored
  2. and the call to “io_saveFile($file,$text);” which will store the wiki-page into $file, where all needed dirs will be created

For now “io_saveFile()” seems of interest and i found it in inc/io.php. There i found how it's done. The call to

io_makeFileDir($file);

creates the needed directory structure upon the given filepath. So this is the function to use in the usermanager plugin.

Now all there is to do is just create the path to the wanted namespace-id, which is in our case “home:<userid>:index”, and create the directory.

One note about the wikiFN-function. If the last part of the argument given is ':', it results in a path where the element just before the ':' is suffixed with '.txt'. I think this is an error, but maybe not… just keep this in mind ! For heavens sake “io_makeFileDir()” expects also a file as last argument, so there is no problem at all.

Now it's time to fill our code into the appropriate functions of /lib/plugins/usermanager/admin.php:

append new function

    /*
     * Create homedir (namespace) for user
     */
    function _createHomedir($user, $name){
 
        $userhome = dirname(wikiFN("home:$user:index"));
        $homebase = dirname($userhome);
 
        // create directory
        if(! @is_dir($userhome)) {
            io_makeFileDir($userhome.'/dummy.txt');
            msg("Homedir for user created", 1);
        }
 
        // copy template from parent (modify this to fit YOUR needs !)
        $userpage = $userhome.'/index.txt';
        if(! @is_file($userpage)){
            $tpl = $homebase.'/template.txt';
            if(@is_file($tpl)) {
                $page = io_readFile($tpl);
                $page = preg_replace('/@USERNAME@/', $name, $page);
                io_saveFile($userpage, $page);
                msg("Template copied to homedir", 1);
            }
        }
    }

change _modifyUser()

        if (empty($newuser)) return false;
 
        # create homedir for new/existing user
        $this->_createHomedir($newuser,$newname);
 
        $changes = array();

change _addUser()

        if (empty($user)) return false;
 
        # create homedir for new/existing user
        $this->_createHomedir($user,$name);
 
        return $this->_auth->createUser($user,$pass,$name,$mail,$grps); 

Comments

Ok, thats it! Please read everything carefully and be aware that if you change the sourcecode of dokuwiki, you are unable to upgrade easily.

  • This should become a standard feature. I created a namespace for myself on the one doku installation I have, but, I just did it by symlinking a dir in my /home in /var/lib/dokuwiki/data/pages. I had to chown it to wwww-data. This bought me more space, too, since / only had 20gb and /home had 180gb. But automagically creating a userpage/profile (à la mediawiki?) and a namespace for users seems incredibly useful to me. tazman
tips/homepages.1377937024.txt.gz · Last modified: 2013-08-31 10:17 by 78.42.65.15

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki