Module HowTo - Account pages




1. Loading the LDAP attributes

Every time the user selects an existing account to modify LAM will load the complete LDAP entry of it. Your module then should select the attributes which are useful for it.
There are two variables in baseModule which should be used to store the attributes. The $attributes variable stores the current attributes including changes the user made. The $orig variable stores the attributes as they were originally when the account was loaded. This allows you to see what changes were made.

The load_attributes() function in your module gets the complete attribute list from LDAP.

Example:

The ieee802Device uses an object class and the 'macAddress' attribute. Therefore we will save this two values.

    /**
    * This function loads all needed attributes into the object.
    *
    * @param array $attr an array as it is retured from ldap_get_attributes
    */
    function load_attributes($attr) {
        $this->attributes['objectClass'] = array();
        $this->attributes['macAddress'] = array();
        $this->orig['objectClass'] = array();
        $this->orig['macAddress'] = array();
        if (isset($attr['objectClass'])) {
            unset($attr['objectClass']['count']);
            $this->attributes['objectClass'] = $attr['objectClass'];
            $this->orig['objectClass'] = $attr['objectClass'];
        }
        if (isset($attr['macAddress'])) {
            unset($attr['macAddress']['count']);
            $this->attributes['macAddress'] = $attr['macAddress'];
            $this->orig['macAddress'] = $attr['macAddress'];
        }
        return 0;
    }


2. Defining pages

You can define multiple subpages for your account page. Usually one page is enough but you may display certain attribute settings on an extra page (e.g. Unix group memberships are on a second page).

The page names are set by pages() which returns an array of names.

Example:

The ieee802Device module needs only one page which is called 'attributes'.

    /**
    * This function returns a list of all account pages in this module.
    */
    function pages() {
        return array('attributes');
    }


3. Page display

Now that you have defined your subpages you will need one function for each page to display it. The function must return meta HTML code as defined in the modules specification.
This function is called display_html_<page name>() where <page name> is the name of your subpage.

Example:

The ieee802Device module has only one subpage called 'attributes'.

The first half of the code displays the existing MAC addresses and the second an input field for new values.
The variable $this->attributes contains the LDAP attributes which are useful for this module.

    /**
    * This function will create the meta HTML code to show a page with all attributes.
    *
    * @param array $post HTTP-POST values
    */
    function display_html_attributes($post) {
        $return = array();
        // list current MACs
        for ($i = 0; $i < sizeof($this->attributes['macAddress']); $i++) {
            $return[] = array(
                0 => array('kind' => 'text', 'text' => _('MAC address')),
                1 => array('kind' => 'input', 'name' => 'macAddress' . $i, 'type' => 'text', 'size' => '17', 'maxlength' => '17', 'value' => $this->attributes['macAddress'][$i]),
                2 => array('kind' => 'input', 'type' => 'submit', 'name' => 'delMAC' . $i, 'value' => _("Remove")),
                3 => array('kind' => 'help', 'value' => 'mac'));
        }
        // input box for new MAC
        $return[] = array(
            0 => array('kind' => 'text', 'text' => _('New MAC address')),
            1 => array('kind' => 'input', 'name' => 'macAddress', 'type' => 'text', 'size' => '17', 'maxlength' => '17', 'value' => ''),
            2 => array('kind' => 'input', 'type' => 'submit', 'name' => 'addMAC', 'value' => _("Add")),
            3 => array('kind' => 'help', 'value' => 'mac'),
            4 => array('kind' => 'input', 'type' => 'hidden', 'value' => sizeof($this->attributes['macAddress']), 'name' => 'mac_number'));
        return $return;
    }


4. Processing input data

Every time the user clicks on a submit button while your page is displayed LAM will call a function in your module.
This function is called process_<page name>() where <page name> is the name of your subpage.

If all input data is ok then return "0" or an array containing no error message. If you return one or more error messages then the user will be redirected to your page.

Example:

The ieee802Device module has only one subpage called 'attributes' and therefore only process_attributes().

The function checks the input fields and fills the LDAP attributes. If all is ok it will enable the user to move to another module page.

    /**
    * Write variables into object and do some regex checks
    *
    * @param array $post HTTP-POST values
    */
    function process_attributes($post) {
        $this->triggered_messages = array();
        $this->attributes['macAddress'] = array();
        // check old MACs
        if (isset($post['mac_number'])) {
            for ($i = 0; $i < $post['mac_number']; $i++) {
                if (isset($post['delMAC' . $i])) continue;
                if (isset($post['macAddress' . $i]) && ($post['macAddress' . $i] != "")) {
                    // check if address has correct format
                    if (!get_preg($post['macAddress' . $i], 'macAddress')) {
                        $message = $this->messages['mac'][0];
                        $message[] = $post['macAddress' . $i];
                        $this->triggered_messages[] = array($message);
                    }
                    $this->attributes['macAddress'][] = $post['macAddress' . $i];
                }
            }
        }
        // check new MAC
        if (isset($post['macAddress']) && ($post['macAddress'] != "")) {
            // check if address has correct format
            if (get_preg($post['macAddress'], 'macAddress')) {
                $this->attributes['macAddress'][] = $post['macAddress'];
            }
            else {
                    $message = $this->messages['mac'][0];
                    $message[] = $post['macAddress'];
                    $this->triggered_messages[] = array($message);
            }
        }
        $this->attributes['macAddress'] = array_unique($this->attributes['macAddress']);
        if (sizeof($this->triggered_messages) > 0) {
            $this->inputCorrect = false;
            return $this->triggered_messages;
        }
        else {
            $this->inputCorrect = true;
            return 0;
        }
    }


5. Defining that your module is ready for LDAP add/modify

Before a new account can be created or modified all modules are asked if they are ready.

There are two functions which control the module status:
The module_ready() function has to return true if the user may move to your module page. If it is false the user will be shown an error message that your module is not yet ready. You can use this if your module depends on input data from other modules (e.g. you need the user name from posixAccount first).
The second function is module_complete(). The user cannot do the LDAP operation if one or more modules return false. This defines if all needed input data for your module was entered.

Example:

The ieee802Device module uses a global variable to store the status: $this->inputCorrect. It is set in process_attributes(). The variable can be preset to true because the MAC address is optional.

    /** used for account pages, true if input data is correct */
    var $inputCorrect = true;

    /**
    * This function returns true if all needed settings are done.
    */
    function module_complete() {
        return $this->inputCorrect;
    }
   
    /**
    * Returns true if all settings on module page are correct.
    */
    function module_ready() {
        return $this->inputCorrect;
    }


6. Saving the LDAP attributes

When all modules report that they are ready for LDAP add/modify and the user clicks on the add/modify button your module will be asked what changes have to be made.
This is done in the function save_attributes() which must be implemented by your module.

Example:

The ieee802Device module saves the attribute states in $attributes and $orig and there are no other DNs which may be modified. Therefore we can use the save_module_attributes() function in accountContainer. You can always access the current accountContainer with $_SESSION[$this->base].

    /**
    * Returns a list of modifications which have to be made to the LDAP account.
    *
    * @return array list of modifications
    * <br>This function returns an array with 3 entries:
    * <br>array( DN1 ('add' => array($attr), 'remove' => array($attr), 'modify' => array($attr)), DN2 .... )
    * <br>DN is the DN to change. It may be possible to change several DNs (e.g. create a new user and add him to some groups via attribute memberUid)
    * <br>"add" are attributes which have to be added to LDAP entry
    * <br>"remove" are attributes which have to be removed from LDAP entry
    * <br>"modify" are attributes which have to been modified in LDAP entry
    */
    function save_attributes() {
        return $_SESSION[$this->base]->save_module_attributes($this->attributes, $this->orig);
    }