diff --git a/README b/README new file mode 100644 index 0000000..3d1fc49 --- /dev/null +++ b/README @@ -0,0 +1,55 @@ +groupmanager +======== + +_groupmanager_ is a simple group manager plugin for dokuwiki. +It is based on the original plugin _groupmgr_ by Alex Forencich. +The original plugin has not been updated since 2010. +It actually even never left the devel-zone, but the idea is great! + +_groupmgr_ allowed easy modification of group membership by non-admins. +This greatly simplifies management of collaborative projects by group-admins. +_groupmanager_ adds functionality from the _usermanager_ by Christopher Smith to the original code of Alex Forencich. +This way users can easily be found and added in wikis with many users. +Also _groupmanager_ can be configured to add or delete users altogether if they are no member of a group. + +Installation +------------ + +Unzip into lib/plugins directory + +Syntax +------ + +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 'groupa' and 'groupb' can be managed by user 'joe' +and members of the group 'admin' + +Notes: + +1. Super user groups can only be managed by super users +2. forbidden_groups configuration setting specifies groups that cannot be + edited with the plugin +3. Users cannot remove themselves from the group that grants them access + to the group manager (including admins) +4. The conf_namespace option specifies a separate namespace for configuration. + When the config namespace is used, a placeholder tag (~~groupmanager~~) can be + used in the actual page while the full tag is placed in the configuration + namespace at config_namespace:ID +5. If require_conf_namespace is set, all configuration options placed in the + page are ignored, necesitating the use of the configuration namespace. + For security reasons, this is the default configuration. + + + + + +This file was modified by IntelliJ IDEA 11.1.3 for binding GitHub repository \ No newline at end of file diff --git a/conf/default.php b/conf/default.php new file mode 100644 index 0000000..1d045da --- /dev/null +++ b/conf/default.php @@ -0,0 +1,13 @@ + + * original author Alex Forencich + */ + +$conf['forbidden_groups'] = ""; +$conf['require_conf_namespace'] = 1; +$conf['conf_namespace'] = "groupmanager"; +$conf['allow_add_user'] = "0"; +$conf['allow_delete_user'] = "0"; diff --git a/conf/metadata.php b/conf/metadata.php new file mode 100644 index 0000000..7d7c022 --- /dev/null +++ b/conf/metadata.php @@ -0,0 +1,15 @@ + + * original author Alex Forencich + */ + + +$meta['forbidden_groups'] = array('string'); +$meta['require_conf_namespace'] = array('onoff'); +$meta['conf_namespace'] = array('string'); +$meta['allow_add_user'] = array('onoff'); +$meta['allow_delete_user'] = array('onoff'); + diff --git a/images/clear.png b/images/clear.png new file mode 100644 index 0000000..36e4583 Binary files /dev/null and b/images/clear.png differ diff --git a/images/clear_small.png b/images/clear_small.png new file mode 100644 index 0000000..05ceb53 Binary files /dev/null and b/images/clear_small.png differ diff --git a/images/clear_small_old.png b/images/clear_small_old.png new file mode 100644 index 0000000..05ceb53 Binary files /dev/null and b/images/clear_small_old.png differ diff --git a/images/everybody.jpg b/images/everybody.jpg new file mode 100644 index 0000000..66a4101 Binary files /dev/null and b/images/everybody.jpg differ diff --git a/images/everybody_hilite.jpg b/images/everybody_hilite.jpg new file mode 100644 index 0000000..090368a Binary files /dev/null and b/images/everybody_hilite.jpg differ diff --git a/images/search.jpg b/images/search.jpg new file mode 100644 index 0000000..315ba45 Binary files /dev/null and b/images/search.jpg differ diff --git a/images/search.png b/images/search.png new file mode 100644 index 0000000..f081968 Binary files /dev/null and b/images/search.png differ diff --git a/images/search_hilite.jpg b/images/search_hilite.jpg new file mode 100644 index 0000000..0b6e2d9 Binary files /dev/null and b/images/search_hilite.jpg differ diff --git a/images/search_small.png b/images/search_small.png new file mode 100644 index 0000000..f78f9be Binary files /dev/null and b/images/search_small.png differ diff --git a/images/workgroup.jpg b/images/workgroup.jpg new file mode 100644 index 0000000..87bfb37 Binary files /dev/null and b/images/workgroup.jpg differ diff --git a/images/workgroup_hilite.jpg b/images/workgroup_hilite.jpg new file mode 100644 index 0000000..7de0db3 Binary files /dev/null and b/images/workgroup_hilite.jpg differ diff --git a/lang/en/add.txt b/lang/en/add.txt new file mode 100644 index 0000000..9afecb5 --- /dev/null +++ b/lang/en/add.txt @@ -0,0 +1 @@ +===== Add user ===== diff --git a/lang/en/delete.txt b/lang/en/delete.txt new file mode 100644 index 0000000..c3ca90d --- /dev/null +++ b/lang/en/delete.txt @@ -0,0 +1 @@ +===== Delete user ===== diff --git a/lang/en/edit.txt b/lang/en/edit.txt new file mode 100644 index 0000000..4d02dfd --- /dev/null +++ b/lang/en/edit.txt @@ -0,0 +1 @@ +===== Edit user ===== diff --git a/lang/en/intro.txt b/lang/en/intro.txt new file mode 100644 index 0000000..73bf556 --- /dev/null +++ b/lang/en/intro.txt @@ -0,0 +1 @@ +====== User Manager ====== diff --git a/lang/en/lang.php b/lang/en/lang.php new file mode 100644 index 0000000..cb6f687 --- /dev/null +++ b/lang/en/lang.php @@ -0,0 +1,77 @@ + + * base on groupmgr by Alex Forencich + */ + +// menu entry for admin plugins +$lang['menu'] = 'Group Manager'; + +// custom language strings for the plugin +$lang['notauthorized'] = 'Error: not authorized'; +$lang['updatesuccess'] = 'Updated successfully'; +$lang['updatefailed'] = 'Update failed'; +$lang['menu'] = 'User Manager'; +$lang['btn_update_group'] = 'Update group'; + +//stolen from usermanager +// custom language strings for the plugin +$lang['noauth'] = '(user authentication not available)'; +$lang['nosupport'] = '(user management not supported)'; + +$lang['badauth'] = 'invalid auth mechanism'; // should never be displayed! + +$lang['user_id'] = 'User'; +$lang['user_pass'] = 'Password'; +$lang['user_name'] = 'Real Name'; +$lang['user_mail'] = 'Email'; +$lang['user_groups'] = 'Groups'; + +$lang['field'] = 'Field'; +$lang['value'] = 'Value'; +$lang['add'] = 'Add User'; +$lang['delete'] = 'Delete'; +$lang['delete_selected'] = 'Delete selected user'; +$lang['edit'] = 'Edit user'; +$lang['edit_prompt'] = 'Edit this user'; +$lang['modify'] = 'Save changes to user'; +$lang['search'] = 'Search for user'; +$lang['search_prompt'] = 'Search with filter-values'; +$lang['search_default_group'] = 'Show only group members'; +$lang['clear'] = 'Show everybody'; +$lang['filter'] = 'Filter list with criteria'; + +$lang['summary'] = 'Displaying users %1$d-%2$d of %3$d found. %4$d users total.'; +$lang['nonefound'] = 'No users found. %d users total.'; +$lang['delete_ok'] = '%d users deleted'; +$lang['delete_fail'] = '%d failed deleting.'; +$lang['update_ok'] = 'User updated successfully'; +$lang['update_fail'] = 'User update failed'; +$lang['update_exists'] = 'User name change failed, the specified user name (%s) already exists (any other changes will be applied).'; +$lang['add_without_form'] = 'Trying to add user without form!'; +$lang['cant_delete_yourself'] = "You can't delete yourself!"; +$lang['cant_delete_if_more_groups'] = "User is part of other groups outside of this working group and can not be deleted"; + +$lang['start'] = 'start'; +$lang['prev'] = 'previous'; +$lang['next'] = 'next'; +$lang['last'] = 'last'; + +// added after 2006-03-09 release +$lang['edit_usermissing'] = 'Selected user not found, the specified user name may have been deleted or changed elsewhere.'; +$lang['user_notify'] = 'Notify user'; +$lang['note_notify'] = 'Notification emails are only sent if the user is given a new password.'; +$lang['note_group'] = 'New users will be added to the default group (%s)'; +$lang['note_pass'] = 'The password will be autogenerated if the field is left empty and notification of the user is enabled.'; +$lang['add_ok'] = 'User added successfully'; +$lang['add_fail'] = 'User addition failed'; +$lang['notify_ok'] = 'Notification email sent'; +$lang['notify_fail'] = 'Notification email could not be sent'; + +// required fields +$lang['mail_required'] = "Mail is required field!"; +$lang['user_must_be_notified_with_generated_pwd'] = "When generating a password the user must be notified! Choose a password yourself or check '".$lang['user_notify']."'."; + +//Setup VIM: ex: et ts=4 enc=utf-8 : diff --git a/lang/en/list.txt b/lang/en/list.txt new file mode 100644 index 0000000..54c45ca --- /dev/null +++ b/lang/en/list.txt @@ -0,0 +1 @@ +===== User List ===== diff --git a/lang/en/settings.php b/lang/en/settings.php new file mode 100644 index 0000000..8d3bccb --- /dev/null +++ b/lang/en/settings.php @@ -0,0 +1,12 @@ + + * original author Alex Forencich + */ + +// for the configuration manager +$lang['forbidden_groups'] = "List of forbidden groups"; +$lang['require_conf_namespace'] = "Require configuration namespace"; +$lang['conf_namespace'] = "Configuration namespace prefix"; \ No newline at end of file diff --git a/manager.dat b/manager.dat new file mode 100644 index 0000000..7334c39 --- /dev/null +++ b/manager.dat @@ -0,0 +1,2 @@ +installed=Wed, 15 Aug 2012 10:59:03 +0200 +url=http://github.com/haraldronge/groupmanager/zipball/master diff --git a/plugin.info.txt b/plugin.info.txt new file mode 100644 index 0000000..c4c278d --- /dev/null +++ b/plugin.info.txt @@ -0,0 +1,9 @@ +base groupmanager +author Harald Ronge +email harald@turtur.nl +date 2010-11-28 +name groupmanager plugin +desc Embeddable group manager +url http://www.turtur.nl/ +original author Alex Forencich + diff --git a/script.js b/script.js new file mode 100644 index 0000000..03241d8 --- /dev/null +++ b/script.js @@ -0,0 +1,30 @@ +/** + * Add JavaScript confirmation to the User Delete button + */ +jQuery(function(){ + jQuery('#usrmgr__del').click(function(){ + return confirm(LANG.del_confirm); + }); +}); + +function MM_swapImgRestore() { //v3.0 + var i,x,a=document.MM_sr; for(i=0;a&&i0&&parent.frames.length) { + d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);} + if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i + * @original author Alex Forencich + * + * 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('DOKU_PLUGIN_IMAGES')) define('DOKU_PLUGIN_IMAGES', DOKU_INC . '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' => '2012-09-01', + 'name' => 'Group Manager Syntax plugin', + 'desc' => 'Embeddable group manager, based on groupmanager and usermanager from Alex Forencich', + 'url' => 'http://www.turtur.nl/', + '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, &$handler) + { +// groupmanager only + $data = array(null, $state, $pos); + + if (strlen($match) == 12) + return $data; + + // Strip away tag + $match = substr($match, 11, -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, &$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], 11, -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 .= "
"; + //TurTur + $renderer->doc .= formSecurityToken(false); + + // open table and print header + if ($this->_user_total > 0) { + $renderer->doc .= "

" . sprintf($this->lang['summary'], $this->_start + 1, $this->_last, $this->_user_total, $this->_auth->getUserCount()) . "

"; + } else { + $renderer->doc .= "

" . sprintf($this->lang['nonefound'], $this->_auth->getUserCount()) . "

"; + } + + $renderer->doc .= "\n"; //width=\"95%\" style=\"max-width: 500px; overflow:scroll;\">\n"; + // $renderer->doc .= " \n"; + $renderer->doc .= " "; + + $renderer->doc .= " "; + $renderer->doc .= " "; + //if delete column is hidden, Filter-header is part of the same column + if ($allow_delete_user) {$renderer->doc .= " ";} + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " \n"; + + $renderer->doc .= " \n"; + if ($allow_delete_user) $renderer->doc .= " \n"; + $renderer->doc .= " \n"; + $renderer->doc .= " \n"; + $renderer->doc .= " \n"; + // loop through available groups + foreach ($this->grplst as $g) { + $renderer->doc .= " \n"; + } + + $renderer->doc .= " \n"; + + + // loop through users + foreach ($this->userlist as $name => $u) { + // print user info + $renderer->doc .= " \n"; + if ($allow_delete_user) $renderer->doc .= ""; + $renderer->doc .= " \n"; + $renderer->doc .= " \n"; + $renderer->doc .= " \n"; + // loop through groups + foreach ($this->grplst as $g) { + $renderer->doc .= " \n"; + } + $renderer->doc .= " \n\n"; + } + + $renderer->doc .= " \n"; + + $renderer->doc .= " "; + $renderer->doc .= " "; + + $renderer->doc .= " "; + + $renderer->doc .= "
"; + $renderer->doc .= " "; + $renderer->doc .= " lang['search_prompt'] . "\" alt=\"" . $this->lang['search'] . "\" />"; + $renderer->doc .= " lang['search_default_group'] . "\" alt=\"" . $this->lang['search_default_group'] . "\" />"; + $renderer->doc .= " lang['clear'] . "\" alt=\"" . $this->lang['clear'] . "\" />"; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " lang['start'] . "\" />"; + $renderer->doc .= " lang['prev'] . "\" />"; + $renderer->doc .= " lang['next'] . "\" />"; + $renderer->doc .= " lang['last'] . "\" />"; + + $renderer->doc .= " "; + $renderer->doc .= "
Filter:_htmlFilter('user') . "\" />_htmlFilter('name') . "\" />_htmlFilter('mail') . "\" />"; + $renderer->doc .= " _htmlFilter('grps') . "\" />
" . $this->lang['delete'] . "" . $this->lang['user_id'] . "" . $this->lang['user_name'] . "" . $this->lang['user_mail'] . "" . ucwords(str_replace("_", " ", str_replace("wg_", "", htmlspecialchars($g)))) . "
" . 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 .= ""; + $renderer->doc .= "" . htmlspecialchars($u['name']) . ""; + $renderer->emaillink($u['mail']); + + $renderer->doc .= ""; + + $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 ($auth->modifyUser($name, $update)) { + if ($status == 0) $status = 1; + } else { + $status = 2; + } + } + } + + // display check box + $renderer->doc .= "doc .= " checked=\"true\""; + } + if ($disabled) { + $renderer->doc .= " disabled=\"true\""; + } + + $renderer->doc .= " />"; + + $renderer->doc .= "
"; + $renderer->doc .= " "; + $renderer->doc .= " lang['search_prompt'] . "\" alt=\"" . $this->lang['search'] . "\" />"; + $renderer->doc .= " lang['search_default_group'] . "\" alt=\"" . $this->lang['search_default_group'] . "\" />"; + $renderer->doc .= " lang['clear'] . "\" alt=\"" . $this->lang['clear'] . "\" />"; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " lang['start'] . "\" />"; + $renderer->doc .= " lang['prev'] . "\" />"; + $renderer->doc .= " lang['next'] . "\" />"; + $renderer->doc .= " lang['last'] . "\" />"; + + $renderer->doc .= " "; + $renderer->doc .= "
\n"; + + $renderer->doc .= "_start . "\" />"; + // update button + $renderer->doc .= "
lang['btn_update_group'] . "\" />
"; + + $renderer->doc .= "
"; + + + if ($this->_auth->canDo('addUser') && $allow_add_user) { + $style = $this->_add_user ? " class=\"add_user\"" : ""; + $renderer->doc .= ""; + $renderer->doc .= $this->locale_xhtml('add'); + $renderer->doc .= "
"; + + $UserData['grps'][0] = $this->DefaultGroup; + $this->_htmlUserForm($renderer, 'add', null, $UserData, 4); + + $renderer->doc .= "
"; + $renderer->doc .= ""; + } + + // 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 .= "

" . $this->lang['notauthorized'] . "

\n"; + } + + return true; + } + return false; + } + + + /** + * @todo disable fields which the backend can't change + */ + 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 .= "
"; + $renderer->doc .= formSecurityToken(false); + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + + $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 .= "_auth->canDo("modPass")) { + $notes[] = $this->lang['note_pass']; + if ($user) { + $notes[] = $this->lang['note_notify']; + } + + $renderer->doc .= ""; + } + + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= " "; + $renderer->doc .= "
" . $this->lang["field"] . "" . $this->lang["value"] . "
"; + + $this->_htmlFilterSettings($renderer, $indent + 10); + + $renderer->doc .= " lang[$cmd] . "\" />"; + $renderer->doc .= "
"; + + foreach ($notes as $note) + $renderer->doc .= "
" . $note . "
"; + + $renderer->doc .= "
"; + } + + 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 .= ""; + $renderer->doc .= ""; + $renderer->doc .= ""; + if ($cando) { + $renderer->doc .= ""; + } else { + $renderer->doc .= ""; + $renderer->doc .= ""; + } + $renderer->doc .= ""; + $renderer->doc .= ""; + } + + 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)) { + 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 .= "_start . "\" />"; + + foreach ($this->_filter as $key => $filter) { + $renderer->doc .= ""; + } + } + + /** + * 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: