<?php /** * DokuWiki Plugin groupmanager (Syntax Component) * * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html * @author Harald Ronge <harald@turtur.nl> * @original author Alex Forencich <alex@alexforencich.com> * * Syntax: * ~~groupmanager|[groups to manage]|[allowed users and groups]~~ * * Examples: * ~~groupmanager|posters|@moderators~~ * Members of group 'posters' can be managed by group 'moderators' * * ~~groupmanager|groupa, groupb|joe, @admin~~ * Members of groups 'groupa' and 'groupb' can be managed by user 'joe' * members of the 'admin' group * * Note: superuser groups can only be managed by super users, * forbidden groups can be configured, * and users cannot remove themselves from the group that lets them access * the group manager (including admins) * * Note: if require_conf_namespace config option is set, then plugin looks in * conf_namespace:$ID for configuration. Plugin will also check config * namespace if a placeholder tag is used (~~groupmanager~~). This is the * default configuration for security reasons. * */ // must be run within Dokuwiki if (!defined('DOKU_INC')) die(); if (!defined('DOKU_LF')) define('DOKU_LF', "\n"); if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t"); if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); if (!defined('GROUPMANAGER_IMAGES')) define('GROUPMANAGER_IMAGES', DOKU_BASE . 'lib/plugins/groupmanager/images/'); require_once DOKU_PLUGIN . 'syntax.php'; function remove_item_by_value($val, $arr, $preserve = true) { if (empty($arr) || !is_array($arr)) { return false; } foreach (array_keys($arr, $val) as $key) { unset($arr[$key]); } return ($preserve) ? $arr : array_values($arr); } class syntax_plugin_groupmanager extends DokuWiki_Syntax_Plugin { /** * Plugin information */ var $_auth = null; // auth object var $_user_total = 0; // number of registered users var $_filter = array(); // user selection filter(s) var $_start = 0; // index of first user to be displayed var $_last = 0; // index of the last user to be displayed var $_pagesize = 20; // number of users to list on one page var $DefaultGroup = ''; var $grplst = array(); var $userlist = array(); /** * Constructor */ function syntax_plugin_groupmanager() { global $auth; $this->setupLocale(); if (!isset($auth)) { $this->disabled = $this->lang['noauth']; } else if (!$auth->canDo('getUsers')) { $this->disabled = $this->lang['nosupport']; } else { // we're good to go $this->_auth = & $auth; } } function getInfo() { return array( 'author' => 'Harald Ronge', 'email' => 'harald@turtur.nl', 'date' => '2013-05-26', 'name' => 'Group Manager Syntax plugin', 'desc' => 'Embeddable group manager, based on groupmgr from Alex Forencich and usermanager from Christopher Smith', 'url' => 'http://www.dokuwiki.org/plugin:groupmanager/', 'original author' => 'Alex Forencich', 'original email' => 'alex@alexforencich.com' ); } /** * Plugin type */ function getType() { return 'substition'; } /** * PType */ function getPType() { return 'normal'; } /** * Sort order */ function getSort() { return 160; } /** * Register syntax handler */ function connectTo($mode) { $this->Lexer->addSpecialPattern('~~groupmanager\|[^~]*?~~', $mode, 'plugin_groupmanager'); $this->Lexer->addSpecialPattern('~~groupmanager~~', $mode, 'plugin_groupmanager'); } /** * Handle match */ // is called without config, but do not know by whom, possibly with literal match function handle($match, $state, $pos, Doku_Handler $handler) { // groupmanager only $data = array(null, $state, $pos); if (strlen($match) == 16) return $data; // Strip away tag $match = substr($match, 15, -2); // split arguments $ar = explode("|", $match); $match = array(); // reorganize into array foreach ($ar as $it) { $ar2 = explode(",", $it); foreach ($ar2 as &$it2) $it2 = trim($it2); $match[] = $ar2; } // pass to render method $data[0] = $match; return $data; } /** * Render it */ function render($mode, Doku_Renderer $renderer, $data) { // start usermanager global $auth; global $lang; global $INFO; global $conf; global $ID; // start groupmanager if ($mode == 'xhtml') { //TurTur, if submit and security token does not match stop anyway if(isset($_REQUEST['fn']) && !checkSecurityToken()) return false; // need config namespace? $allow_add_user = $conf_namespace = $this->getConf('allow_add_user'); $allow_delete_user = $conf_namespace = $this->getConf('allow_delete_user'); $conf_namespace = $this->getConf('conf_namespace'); if ($this->getConf('require_conf_namespace')) { if (!$conf_namespace) return false; else $data[0] = null; // set it to null, it will be reloaded anyway } // empty tag? if (is_null($data[0]) || count($data[0]) == 0) { // load from conf namespace // build page name $conf_page = ""; if (substr($ID, 0, strlen($conf_namespace)) != $conf_namespace) { $conf_page .= $conf_namespace; if (substr($conf_page, -1) != ':') $conf_page .= ":"; } $conf_page .= $ID; // get file name $fn = wikiFN($conf_page); if (!file_exists($fn)) return false; // read file $page = file_get_contents($fn); // find config tag $i = preg_match('/~~groupmanager\|[^~]*?~~/', $page, $match); if ($i == 0) return false; // parse config $match = substr($match[0], 15, -2); $ar = explode("|", $match); $match = array(); // reorganize into array foreach ($ar as $it) { $ar2 = explode(",", $it); foreach ($ar2 as &$it2) $it2 = trim($it2); $match[] = $ar2; } // pass to render method $data[0] = $match; } // don't render if an argument hasn't been specified if (!isset($data[0][0]) || !isset($data[0][1])) return false; $this->grplst = $data[0][0]; $authlst = $data[0][1]; // parse forbidden groups $forbiddengrplst = array(); $str = $this->getConf('forbidden_groups'); if (isset($str)) { $arr = explode(",", $str); foreach ($arr as $val) { $val = trim($val); $forbiddengrplst[] = $val; } } // parse admin groups $admingrplst = array(); if (isset($conf['superuser'])) { $arr = explode(",", $conf['superuser']); foreach ($arr as $val) { $val = trim($val); if ($val[0] == "@") { $val = substr($val, 1); $admingrplst[] = $val; } } } // forbid admin groups if user is not a superuser if (!$INFO['isadmin']) { foreach ($admingrplst as $val) { $forbiddengrplst[] = $val; } } // remove forbidden groups from group list foreach ($forbiddengrplst as $val) { $this->grplst = remove_item_by_value($val, $this->grplst, false); } if (count($this->grplst) > 0) $this->DefaultGroup = $this->grplst[0]; // build array of user's credentials $check = array($_SERVER['REMOTE_USER']); if (is_array($INFO['userinfo'])) { foreach ($INFO['userinfo']['grps'] as $val) { $check[] = "@" . $val; } } // does user have permission? // Also, save authenticated group for later $authbygrp = ""; $ok = 0; foreach ($authlst as $val) { if (in_array($val, $check)) { $ok = 1; if ($val[0] == "@") { $authbygrp = substr($val, 1); } } } // continue if user has explicit permission or is an admin if ($INFO['isadmin'] || $ok) { // authorized $status = 0; // Begin inserted from usermanager if (is_null($this->_auth)) return false; // extract the command and any specific parameters // submit button name is of the form - fn[cmd][param(s)] $fn = $_REQUEST['fn']; if (is_array($fn)) { $cmd = key($fn); $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; } else { $cmd = $fn; $param = null; } if ($cmd != "search") { if (!empty($_REQUEST['start'])) { $this->_start = $_REQUEST['start']; } $this->_filter = $this->_retrieveFilter(); $this->_setFilter("new"); } switch ($cmd) { case "add" : if ($allow_add_user) { $this->_addUser(); } else msg($this->lang['add_without_form'], -1); break; case "update" : $this->_deleteUser(); break; /* //case "add" : if ($allow_add_user) {$this->_addUser()} else msg('Trying to add user without form!',-1); break;/* case "modify" : $this->_modifyUser(); break; case "edit" : $this->_editUser($param); break; */ case "search" : $this->_setFilter($param); $this->_start = 0; break; } /* else { $this->_setFilter($param); $this->_start = 0; } */ $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1; // page handling switch ($cmd) { case 'start' : $this->_start = 0; break; // case 'update' : $this->_start = $this->_start; break; //do nothing case 'prev' : $this->_start -= $this->_pagesize; break; case 'next' : $this->_start += $this->_pagesize; break; case 'last' : $this->_start = $this->_user_total; break; } $this->_validatePagination(); // we are parsing a submitted comment... if (isset($_REQUEST['comment'])) return false; // disable caching $renderer->info['cache'] = false; if (!method_exists($auth, "retrieveUsers")) return false; if (is_null($this->_auth)) { print $this->lang['badauth']; return false; } // watch out: plain authentication takes limit = 0 for get all users // MySQL will take 0 to retrieve none (makes sense), so the code below did not work // $users = $auth->retrieveUsers(0, 10000, array()); $this->userlist = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter); $page_buttons = $this->_pagination(); $colspan = 4 + count($this->grplst) + ($allow_delete_user?0:-1) ; // open form $renderer->doc .= "<form method=\"post\" action=\"" . htmlspecialchars($_SERVER['REQUEST_URI']) . "\" name=\"groupmanager\" enctype=\"application/x-www-form-urlencoded\">"; //TurTur $renderer->doc .= formSecurityToken(false); // open table and print header if ($this->_user_total > 0) { $renderer->doc .= "<p>" . sprintf($this->lang['summary'], $this->_start + 1, $this->_last, $this->_user_total, $this->_auth->getUserCount()) . "</p>"; } else { $renderer->doc .= "<p>" . sprintf($this->lang['nonefound'], $this->_auth->getUserCount()) . "</p>"; } $renderer->doc .= "<table class=\"inline\" >\n"; //width=\"95%\" style=\"max-width: 500px; overflow:scroll;\">\n"; // $renderer->doc .= " <tbody>\n"; $renderer->doc .= " <tbody>"; $renderer->doc .= " <tr><td colspan=\"" . $colspan . "\" class=\"centeralign\" STYLE='border-bottom: 3px solid #ccc'>"; $renderer->doc .= " <span class=\"medialeft\" >"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "search.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "search_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "search.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][new]\" title=\"" . $this->lang['search_prompt'] . "\" alt=\"" . $this->lang['search'] . "\" />"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "workgroup.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "workgroup_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "workgroup.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][show_default]\" title=\"" . $this->lang['search_default_group'] . "\" alt=\"" . $this->lang['search_default_group'] . "\" />"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "everybody.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "everybody_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "everybody.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][clear]\" title=\"" . $this->lang['clear'] . "\" alt=\"" . $this->lang['clear'] . "\" />"; $renderer->doc .= " </span>"; $renderer->doc .= " <span class=\"mediaright\">"; $renderer->doc .= " <input type=\"submit\" name=\"fn[start]\" " . $page_buttons['start'] . " class=\"button\" value=\"" . $this->lang['start'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[prev]\" " . $page_buttons['prev'] . " class=\"button\" value=\"" . $this->lang['prev'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[next]\" " . $page_buttons['next'] . " class=\"button\" value=\"" . $this->lang['next'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[last]\" " . $page_buttons['last'] . " class=\"button\" value=\"" . $this->lang['last'] . "\" />"; $renderer->doc .= " </span>"; $renderer->doc .= " </td></tr>"; $renderer->doc .= " <tr>"; //if delete column is hidden, Filter-header is part of the same column if ($allow_delete_user) {$renderer->doc .= " <td STYLE='border-bottom: 3px solid #ccc; color: #FF9900'> Filter:</td>";} $renderer->doc .= " <td class=\"centeralign\" style=\"border-bottom: 3px solid #ccc\"><input type=\"text\" style=\"width:90%; color: #FF9900';\" name=\"userid\" class=\"edit\" value=\"" . $this->_htmlFilter('user') . "\" /></td>"; $renderer->doc .= " <td class=\"centeralign\" style=\"border-bottom: 3px solid #ccc\"><input type=\"text\" style=\"width:90%; color: #FF9900';\" name=\"username\" class=\"edit\" value=\"" . $this->_htmlFilter('name') . "\" /></td>"; $renderer->doc .= " <td style=\"border-bottom: 3px solid #ccc\"><input type=\"text\" style=\"width:90%; color: #FF9900';\" name=\"usermail\" class=\"edit\" value=\"" . $this->_htmlFilter('mail') . "\" /></td>"; $renderer->doc .= " <td colspan=\"" . $colspan . "\" class=\"centeralign\" style=\"border-bottom: 3px solid #ccc\">"; $renderer->doc .= " <span> <input type=\"text\" style=\"width:95%; color: #FF9900';\" name=\"usergroups\" class=\"edit\" value=\"" . $this->_htmlFilter('grps') . "\" /></span></td>"; $renderer->doc .= " </tr>\n"; $renderer->doc .= " <tr>\n"; if ($allow_delete_user) $renderer->doc .= " <th style='color: #FF9900'>" . $this->lang['delete'] . "</th>\n"; $renderer->doc .= " <th>" . $this->lang['user_id'] . "</th>\n"; $renderer->doc .= " <th>" . $this->lang['user_name'] . "</th>\n"; $renderer->doc .= " <th>" . $this->lang['user_mail'] . "</th>\n"; // loop through available groups foreach ($this->grplst as $g) { $renderer->doc .= " <th>" . ucwords(str_replace("_", " ", str_replace("wg_", "", htmlspecialchars($g)))) . "</th>\n"; } $renderer->doc .= " </tr>\n"; // loop through users foreach ($this->userlist as $name => $u) { // print user info $renderer->doc .= " <tr>\n"; if ($allow_delete_user) $renderer->doc .= "<td class=\"centeralign\"><input type=\"checkbox\" name=\"delete[" . $name . "]\" /></td>"; $renderer->doc .= " <td>" . htmlspecialchars($name); // need tag so user isn't pulled out of a group if it was added // between initial page load and update //change TurTur: //$hn = md5($name); // caused trouble, on dreamhost md5 did not work //output is better readable too //end change $renderer->doc .= "<input type=\"hidden\" name=\"id_" . $name . "\" value=\"1\" />"; $renderer->doc .= "</td>\n"; $renderer->doc .= " <td>" . htmlspecialchars($u['name']) . "</td>\n"; $renderer->doc .= " <td>"; $renderer->emaillink($u['mail']); $renderer->doc .= "</td>\n"; // loop through groups foreach ($this->grplst as $g) { $renderer->doc .= " <td class=\"centeralign\">"; $chk = "chk_" . $name . "_" . $g; // does this box need to be disabled? // prevents user from taking himself out of an important group $disabled = 0; // if this box applies to a current group membership of the current user, continue check if (in_array($g, $u['grps']) && $_SERVER['REMOTE_USER'] == $name) { // if user is an admin and group is an admin group, disable if ($INFO['isadmin'] && in_array($g, $admingrplst)) { $disabled = 1; // if user was authenticated by this group, disable } else if (strlen($authbygrp) > 0 && $g == $authbygrp) { $disabled = 1; } } // update user group membership // only update if something changed // keep track of status $update = array(); if (!$disabled && $_POST["id_" . $name]) { if ($_POST[$chk]) { if (!in_array($g, $u['grps'])) { $u['grps'][] = $g; $update['grps'] = $u['grps']; } } else { if (in_array($g, $u['grps'])) { $u['grps'] = remove_item_by_value($g, $u['grps'], false); $update['grps'] = $u['grps']; } } if (count($update) > 0) { if ($this->_auth->triggerUserMod('modify',array($name, $update))) { io_saveFile($conf['cachedir'] . '/sessionpurge', time()); //invalidate all sessions if ($status == 0) $status = 1; } else { $status = 2; } } } // display check box $renderer->doc .= "<input type=\"checkbox\" name=\"" . $chk . "\""; if (in_array($g, $u['grps'])) { $renderer->doc .= " checked=\"true\""; } if ($disabled) { $renderer->doc .= " disabled=\"true\""; } $renderer->doc .= " />"; $renderer->doc .= "</td>\n"; } $renderer->doc .= " </tr>\n\n"; } $renderer->doc .= " </tbody>\n"; $renderer->doc .= " <tbody>"; $renderer->doc .= " <tr><td colspan=\"" . $colspan . "\" class=\"centeralign\" STYLE='border-top: 3px solid #ccc'>"; $renderer->doc .= " <span class=\"medialeft\">"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "search.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "search_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "search.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][new]\" title=\"" . $this->lang['search_prompt'] . "\" alt=\"" . $this->lang['search'] . "\" />"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "workgroup.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "workgroup_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "workgroup.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][show_default]\" title=\"" . $this->lang['search_default_group'] . "\" alt=\"" . $this->lang['search_default_group'] . "\" />"; $renderer->doc .= " <input type=\"image\" src=\"" . GROUPMANAGER_IMAGES . "everybody.png\" onmouseover=\"this.src='" . GROUPMANAGER_IMAGES . "everybody_hilite.png'\" onmouseout=\"this.src='" . GROUPMANAGER_IMAGES . "everybody.png'\" STYLE=\"float: left; padding-right: 5px;\" name=\"fn[search][clear]\" title=\"" . $this->lang['clear'] . "\" alt=\"" . $this->lang['clear'] . "\" />"; $renderer->doc .= " </span>"; $renderer->doc .= " <span class=\"mediaright\">"; $renderer->doc .= " <input type=\"submit\" name=\"fn[start]\" " . $page_buttons['start'] . " class=\"button\" value=\"" . $this->lang['start'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[prev]\" " . $page_buttons['prev'] . " class=\"button\" value=\"" . $this->lang['prev'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[next]\" " . $page_buttons['next'] . " class=\"button\" value=\"" . $this->lang['next'] . "\" />"; $renderer->doc .= " <input type=\"submit\" name=\"fn[last]\" " . $page_buttons['last'] . " class=\"button\" value=\"" . $this->lang['last'] . "\" />"; $renderer->doc .= " </span>"; $renderer->doc .= " </td></tr>"; $renderer->doc .= " </tbody>"; $renderer->doc .= "</table>\n"; $renderer->doc .= "<input type=\"hidden\" name=\"start\" value=\"" . $this->_start . "\" />"; // update button $renderer->doc .= "<div><input type=\"submit\" name=\"fn[update]\" " . $page_buttons['update'] . " class=\"button\" value=\"" . $this->lang['btn_update_group'] . "\" /></div>"; $renderer->doc .= "</form>"; if ($this->_auth->canDo('addUser') && $allow_add_user) { $style = $this->_add_user ? " class=\"add_user\"" : ""; $renderer->doc .= "<div" . $style . ">"; $renderer->doc .= $this->locale_xhtml('add'); $renderer->doc .= " <div class=\"level2\">"; $UserData['grps'][0] = $this->DefaultGroup; $this->_htmlUserForm($renderer, 'add', null, $UserData, 4); $renderer->doc .= " </div>"; $renderer->doc .= "</div>"; } // display relevant status message if ($status == 1) { msg($this->lang['updatesuccess'], 1); } else if ($status == 2) { msg($this->lang['updatefailed'], -1); } } else { // not authorized $renderer->doc .= "<p>" . $this->lang['notauthorized'] . "</p>\n"; } return true; } return false; } function _htmlUserForm(&$renderer, $cmd, $user = '', $userdata = array(), $indent = 0) { global $conf; global $ID; $name = $mail = $groups = ''; $notes = array(); extract($userdata); if (!empty($grps)) $groups = join(',', $grps); if (!$user) { //$groups will contain the default group when users are added $notes[] = sprintf($this->lang['note_group'], $groups); } $renderer->doc .= "<form action=\"" . wl($ID) . "\" method=\"post\">"; $renderer->doc .= formSecurityToken(false); $renderer->doc .= " <table class=\"inline\" width='75%'>"; $renderer->doc .= " <thead>"; $renderer->doc .= " <tr><th>" . $this->lang["field"] . "</th><th>" . $this->lang["value"] . "</th></tr>"; $renderer->doc .= " </t>"; $renderer->doc .= " <tbody>"; $this->_htmlInputField($renderer, $cmd . "_userid", "userid", $this->lang["user_id"], $user, $this->_auth->canDo("modLogin"), $indent + 6); $this->_htmlInputField($renderer, $cmd . "_userpass", "userpass", $this->lang["user_pass"], "", $this->_auth->canDo("modPass"), $indent + 6); $this->_htmlInputField($renderer, $cmd . "_username", "username", $this->lang["user_name"], $name, $this->_auth->canDo("modName"), $indent + 6); $this->_htmlInputField($renderer, $cmd . "_usermail", "usermail", $this->lang["user_mail"], $mail, $this->_auth->canDo("modMail"), $indent + 6); $renderer->doc .= "<input type='hidden' id='" . $cmd . "_usergroups' name='usergroups' value='" . $groups . "'"; if ($this->_auth->canDo("modPass")) { $notes[] = $this->lang['note_pass']; if ($user) { $notes[] = $this->lang['note_notify']; } $renderer->doc .= "<tr><td><label for=\"" . $cmd . "_usernotify\" >" . $this->lang["user_notify"] . ": </label></td><td><input type=\"checkbox\" id=\"" . $cmd . "_usernotify\" name=\"usernotify\" value=\"1\" /></td></tr>"; } $renderer->doc .= " </tbody>"; $renderer->doc .= " <tbody>"; $renderer->doc .= " <tr>"; $renderer->doc .= " <td colspan=\"2\">"; $this->_htmlFilterSettings($renderer, $indent + 10); $renderer->doc .= " <input type=\"submit\" name=\"fn[" . $cmd . "]\" class=\"button\" value=\"" . $this->lang[$cmd] . "\" />"; $renderer->doc .= " </td>"; $renderer->doc .= " </tr>"; $renderer->doc .= " </tbody>"; $renderer->doc .= " </table>"; foreach ($notes as $note) $renderer->doc .= "<div class=\"fn\">" . $note . "</div>"; $renderer->doc .= "</form>"; } function _htmlInputField(&$renderer, $id, $name, $label, $value, $cando, $indent = 0) { $class = $cando ? '' : ' class="disabled"'; $disabled = $cando ? '' : ' disabled="disabled"'; $renderer->doc .= str_pad('', $indent); if ($name == 'userpass') { $fieldtype = 'password'; $autocomp = 'autocomplete="off"'; } else { $fieldtype = 'text'; $autocomp = ''; } $renderer->doc .= "<tr $class>"; $renderer->doc .= "<td style='width: 30%'><label for=\"$id\" >$label: </label></td>"; $renderer->doc .= "<td>"; if ($cando) { $renderer->doc .= "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit\" $autocomp style='width: 95%'/>"; } else { $renderer->doc .= "<input type=\"hidden\" name=\"$name\" value=\"$value\" />"; $renderer->doc .= "<input type=\"$fieldtype\" id=\"$id\" name=\"$name\" value=\"$value\" class=\"edit disabled\" disabled=\"disabled\" />"; } $renderer->doc .= "</td>"; $renderer->doc .= "</tr>"; } function _addUser() { if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('addUser')) return false; list($user, $pass, $name, $mail, $grps) = $this->_retrieveUser(); if (empty($user)) return false; if ($this->_auth->canDo('modPass')) { if (empty($pass)) { if (!empty($_REQUEST['usernotify'])) { $pass = auth_pwgen(); } else { msg($this->lang['user_must_be_notified_with_generated_pwd'], -1); msg($this->lang['add_fail'], -1); return false; } } } else { if (!empty($pass)) { msg($this->lang['add_fail'], -1); return false; } } if ($this->_auth->canDo('modName')) { if (empty($name)) { msg($this->lang['add_fail'], -1); return false; } } else { if (!empty($name)) { return false; } } if ($this->_auth->canDo('modMail')) { if (empty($mail)) { msg($this->lang['mail_required'], -1); msg($this->lang['add_fail'], -1); return false; } } else { if (!empty($mail)) { return false; } } if ($ok = $this->_auth->triggerUserMod('create', array($user, $pass, $name, $mail, $grps))) { msg($this->lang['add_ok'], 1); if (!empty($_REQUEST['usernotify']) && $pass) { $this->_notifyUser($user, $pass); } } else { msg($this->lang['add_fail'], -1); } return $ok; } /** * Delete user */ function _deleteUser() { global $conf; //$MayDelete = false; if (!checkSecurityToken()) return false; if (!$this->_auth->canDo('delUser')) return false; $selected = $_REQUEST['delete']; if (!is_array($selected) || empty($selected)) return false; $selected = array_keys($selected); if (in_array($_SERVER['REMOTE_USER'], $selected)) { msg($this->lang['cant_delete_yourself'], -1); return false; } //user may only be deleted if not member of any group other than the current working group roles foreach ($selected as $selection) { $currentfilter['user'] = $selection; $currentuser = $this->_auth->retrieveUsers(0, 100000, $currentfilter); $currentgroups = $currentuser[$selection]['grps']; //user may only be part of working group parts //if (count($currentgroups) <= count($this->grplst)) { commented out, If the user is in more groups than this page manages it would skip the test to see if the user was in any other groups! foreach ($currentgroups as $g) { if (!in_array($g, $this->grplst)) { msg($this->lang['cant_delete_if_more_groups'], -1); return false; } } //} } $count = $this->_auth->triggerUserMod('delete', array($selected)); if ($count == count($selected)) { $text = str_replace('%d', $count, $this->lang['delete_ok']); msg("$text.", 1); } else { $part1 = str_replace('%d', $count, $this->lang['delete_ok']); $part2 = str_replace('%d', (count($selected) - $count), $this->lang['delete_fail']); msg("$part1, $part2", -1); } // invalidate all sessions io_saveFile($conf['cachedir'] . '/sessionpurge', time()); return true; } /** * send password change notification email */ function _notifyUser($user, $password) { if ($sent = auth_sendPassword($user, $password)) { msg($this->lang['notify_ok'], 1); } else { msg($this->lang['notify_fail'], -1); } return $sent; } function _htmlFilter($key) { if (empty($this->_filter)) return ''; return (isset($this->_filter[$key]) ? hsc($this->_filter[$key]) : ''); } function _htmlFilterSettings(&$renderer, $indent = 0) { $renderer->doc .= "<input type=\"hidden\" name=\"start\" value=\"" . $this->_start . "\" />"; foreach ($this->_filter as $key => $filter) { $renderer->doc .= "<input type=\"hidden\" name=\"filter[" . $key . "]\" value=\"" . hsc($filter) . "\" />"; } } /** * retrieve & clean user data from the form * * @return array(user, password, full name, email, array(groups)) */ function _retrieveUser($clean = true) { global $auth; $user[0] = ($clean) ? $auth->cleanUser($_REQUEST['userid']) : $_REQUEST['userid']; $user[1] = $_REQUEST['userpass']; $user[2] = $_REQUEST['username']; $user[3] = $_REQUEST['usermail']; $user[4] = explode(',', $_REQUEST['usergroups']); $user[4] = array_map('trim', $user[4]); if ($clean) $user[4] = array_map(array($auth, 'cleanGroup'), $user[4]); $user[4] = array_filter($user[4]); $user[4] = array_unique($user[4]); if (!count($user[4])) $user[4] = null; return $user; } function _setFilter($op) { $this->_filter = array(); switch ($op) { case 'clear': break; case 'new': list($user, $pass, $name, $mail, $grps) = $this->_retrieveUser(false); if (!empty($user)) $this->_filter['user'] = str_replace(' ', '_', $user); if (!empty($name)) $this->_filter['name'] = $name; if (!empty($mail)) $this->_filter['mail'] = $mail; if (!empty($grps)) $this->_filter['grps'] = str_replace(' ', '_', join('|', $grps)); //if (!empty($grps)) $this->_filter['grps'] = join('|',$grps); break; case show_default: $this->_filter['grps'] = $this->DefaultGroup; break; } } function _retrieveFilter() { $t_filter = $_REQUEST['filter']; if (!is_array($t_filter)) return array(); // messy, but this way we ensure we aren't getting any additional crap from malicious users $filter = array(); if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps']; return $filter; } function _validatePagination() { if ($this->_start >= $this->_user_total) { $this->_start = $this->_user_total - $this->_pagesize; } if ($this->_start < 0) $this->_start = 0; $this->_last = min($this->_user_total, $this->_start + $this->_pagesize); } /* * return an array of strings to enable/disable pagination buttons */ function _pagination() { $disabled = 'disabled="disabled"'; $buttons['start'] = $buttons['prev'] = ($this->_start == 0) ? $disabled : ''; if ($this->_user_total == -1) { $buttons['last'] = $disabled; $buttons['next'] = ''; } else { $buttons['last'] = $buttons['next'] = (($this->_start + $this->_pagesize) >= $this->_user_total) ? $disabled : ''; } $buttons['update'] = ''; return $buttons; } } // vim:ts=4:sw=4:et:enc=utf-8: