/~enabled/smd_user_manager.php
PHP | 2136 lines | 1610 code | 314 blank | 212 comment | 311 complexity | ccada1338aa7ebb75141582e43475df6 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php
- // This is a PLUGIN TEMPLATE for Textpattern CMS.
- // Copy this file to a new name like abc_myplugin.php. Edit the code, then
- // run this file at the command line to produce a plugin for distribution:
- // $ php abc_myplugin.php > abc_myplugin-0.1.txt
- // Plugin name is optional. If unset, it will be extracted from the current
- // file name. Plugin names should start with a three letter prefix which is
- // unique and reserved for each plugin author ("abc" is just an example).
- // Uncomment and edit this line to override:
- $plugin['name'] = 'smd_user_manager';
- // Allow raw HTML help, as opposed to Textile.
- // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
- // 1 = Plugin help is in raw HTML. Not recommended.
- # $plugin['allow_html_help'] = 1;
- $plugin['version'] = '0.20';
- $plugin['author'] = 'Stef Dawson';
- $plugin['author_uri'] = 'http://stefdawson.com/';
- $plugin['description'] = 'Manage user accounts, groups and privileges';
- // Plugin load order:
- // The default value of 5 would fit most plugins, while for instance comment
- // spam evaluators or URL redirectors would probably want to run earlier
- // (1...4) to prepare the environment for everything else that follows.
- // Values 6...9 should be considered for plugins which would work late.
- // This order is user-overrideable.
- $plugin['order'] = '8';
- // Plugin 'type' defines where the plugin is loaded
- // 0 = public : only on the public side of the website (default)
- // 1 = public+admin : on both the public and admin side
- // 2 = library : only when include_plugin() or require_plugin() is called
- // 3 = admin : only on the admin side (no AJAX)
- // 4 = admin+ajax : only on the admin side (AJAX supported)
- // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
- $plugin['type'] = '5';
- // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
- // Use an appropriately OR-ed combination of these flags.
- // The four high-order bits 0xf000 are available for this plugin's private use
- if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
- if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
- $plugin['flags'] = '3';
- // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
- // Syntax:
- // ## arbitrary comment
- // #@event
- // #@language ISO-LANGUAGE-CODE
- // abc_string_name => Localized String
- $plugin['textpack'] = <<<EOT
- #@smd_um
- smd_um_active => Users currently active:
- smd_um_active_timeout => Activity timeout (seconds)
- smd_um_admin_group => Protected administrator group
- smd_um_article_count => Articles
- smd_um_based_on => based on
- smd_um_chp_lbl => Change pass
- smd_um_file_count => Files
- smd_um_grp_affected => . Users affected: {num}
- smd_um_grp_created => Group "{name}" created
- smd_um_grp_deleted => Group deleted
- smd_um_grp_exists => Group already exists as priv ID {id}
- smd_um_grp_lbl => Groups
- smd_um_grp_new => New group title
- smd_um_grp_new_name => name
- smd_um_grp_saved => Group info updated
- smd_um_heading_grp => User groups
- smd_um_heading_prf => User manager settings
- smd_um_heading_prv => User privileges
- smd_um_heading_usr => User management
- smd_um_hierarchical_groups => Assume hierarchical groups (levels)
- smd_um_image_count => Images
- smd_um_link_count => Links
- smd_um_max_search_limit => Maximum user search result limit
- smd_um_name_required => A name is required
- smd_um_new_user => New user
- smd_um_pass_change_error => Password NOT saved
- smd_um_pass_length => Password length (characters)
- smd_um_prf_lbl => Prefs
- smd_um_prv_created => Priv area "{area}" created
- smd_um_prv_exists => Priv area already exist
- smd_um_prv_lbl => Privs
- smd_um_prv_new => New priv area
- smd_um_prv_saved => Privs updated
- smd_um_prv_smd_um => Cannot create privs for smd_user_manager
- smd_um_reset => [R]
- smd_um_self_alter => Allow smd_um privs to be altered
- smd_um_sel_all => Select the entire area then (c)heck, (u)ncheck or (t)oggle highlighted checkboxes
- smd_um_sel_grp => Select this group then (c)heck, (u)ncheck or (t)oggle highlighted checkboxes
- smd_um_sel_prv => Select this area set then (c)heck, (u)ncheck or (t)oggle highlighted checkboxes
- smd_um_sel_reset => Reset: any checked area sets will revert to their defaults after Save
- smd_um_settings => Settings
- smd_um_tab_name => User manager
- smd_um_tbl_installed => Tables installed
- smd_um_tbl_not_installed => Tables not installed
- smd_um_tbl_not_removed => Tables not removed
- smd_um_tbl_removed => Tables removed
- smd_um_user_count => Users in this group:
- smd_um_usr_lbl => Users
- EOT;
- if (!defined('txpinterface'))
- @include_once('zem_tpl.php');
- # --- BEGIN PLUGIN CODE ---
- /**
- * smd_user_manager
- *
- * A Textpattern CMS plugin for complete user administration:
- * -> Search / filter / alter info on users (with asset counts)
- * -> Create / alter groups (roles)
- * -> Create / customise privs (areas)
- * -> Online user list
- *
- * @author Stef Dawson
- * @link http://stefdawson.com/
- */
- // TODO:
- // -> Why does multi-edit fire twice? Is it still attached to the Admin->Users table?
- if (!defined('SMD_UM_PRIVS')) {
- define("SMD_UM_PRIVS", 'smd_um_privs');
- }
- if (!defined('SMD_UM_GROUPS')) {
- define("SMD_UM_GROUPS", 'smd_um_groups');
- }
- if(@txpinterface == 'admin') {
- global $smd_um_event, $txp_permissions, $txp_groups, $txp_user, $step;
- $smd_um_event = 'smd_um';
- add_privs($smd_um_event.'.usr.list', '1, 2, 3');
- add_privs($smd_um_event.'.usr.edit', '1, 2');
- add_privs($smd_um_event.'.usr.create', '1');
- add_privs($smd_um_event.'.grp', '1');
- add_privs($smd_um_event.'.prv', '1');
- add_privs($smd_um_event.'.prf', '1');
- add_privs('plugin_prefs.smd_user_manager', '1');
- register_tab('admin', $smd_um_event, gTxt('smd_um_tab_name'));
- register_callback('smd_um_silence', 'admin');
- register_callback('smd_um_dispatcher', $smd_um_event);
- register_callback('smd_um_dispatcher', $smd_um_event.'.usr.edit.own');
- register_callback('smd_um_users_tab', 'admin_side', 'head_end');
- register_callback('smd_um_prefs', 'plugin_prefs.smd_user_manager');
- register_callback('smd_um_welcome', 'plugin_lifecycle.smd_user_manager');
- register_callback('smd_um_inject_css', 'admin_side', 'head_end');
- // Log the time of this access attempt
- $curr_users = unserialize(get_pref('smd_um_current_users', ''));
- $curr_users[$txp_user] = time();
- set_pref('smd_um_current_users', serialize($curr_users), 'smd_um', PREF_HIDDEN, '', 0);
- // Merge in the groups only for now
- smd_um_priv_merge(1, 0);
- include_once txpath.'/lib/txplib_admin.php';
- // Permit user self-editing
- $smd_um_grps = array_keys(smd_um_get_groups(0));
- unset($smd_um_grps[0]); // Remove None user
- $allprivs = join(',',$smd_um_grps);
- add_privs($smd_um_event, $allprivs); // Required to display anything at all on the User Manager tab
- add_privs($smd_um_event.'.usr.edit.own', $allprivs);
- // Now the privs are established for all admin steps so we can go ahead
- // and merge in the changes. One caveat: if we're saving the privs we
- // need to delay the database merge until after the resets have been applied,
- // otherwise we won't know what the defaults (in admin_config.php) are
- $do_privs = (($step == 'smd_um_privs') && ps('smd_um_priv_save')) ? 0 : 1;
- smd_um_priv_merge(0, $do_privs);
- }
- // ********************
- // ADMIN SIDE INTERFACE
- // ********************
- // -------------------------------------------------------------
- // CSS definitions: hopefully kind to themers
- // Includes a hack for Remora (#nav li ul) to prevent menu from disappearing under the
- // privs content. This only occurs because the .smd_um_privgroup class uses position:relative.
- // Needs workaround as it affects other plugins.
- function smd_um_get_style_rules() {
- $smd_um_styles = array(
- 'control-panel' => '
- .smd_um_privgroup { margin:10px auto; width:50%; position:relative; }
- .smd_um_privgroup h3 { text-align:left; font-weight:bold; }
- .smd_um_privsave { position:absolute; left:-55px; top:0; }
- .smd_um_active_users { margin:15px auto; width:80%; text-align:center; }
- .smd_um_selected { background-color:#e2dfce; }
- .smd_um_grp_name, .smd_um_prv_name, .smd_um_reset_col { cursor:pointer; }
- .smd_um_checkbox, .smd_um_prv_hdr { text-align:center!important; }
- #nav li ul { z-index:10000; }
- ',
- );
- return $smd_um_styles;
- }
- // -------------------------------------------------------------
- function smd_um_inject_css($evt, $stp) {
- global $smd_um_event, $event;
- if ($event == $smd_um_event || $event == 'admin') {
- $smd_um_styles = smd_um_get_style_rules();
- echo '<style type="text/css">', $smd_um_styles['control-panel'], '</style>';
- }
- return;
- }
- // -------------------------------------------------------------
- // Destroy the existing Admin->Users tab if we come from any smd_um-initiated step
- function smd_um_silence($evt, $stp) {
- global $event, $smd_um_event;
- $ignore = array(
- 'author_list',
- 'author_edit',
- 'author_save',
- 'author_save_new',
- 'change_pass',
- );
- $no_dispatch = array(
- 'change_pass',
- );
- if (!in_array($stp, $ignore)) {
- ob_end_clean(); // Kill any existing Admin tab panel...
- ob_start(); // ... and start again
- $event = $smd_um_event;
- if (!in_array($stp, $no_dispatch)) {
- smd_um_dispatcher($event, $stp);
- }
- }
- }
- // -------------------------------------------------------------
- // Plugin jump off point
- function smd_um_dispatcher($evt, $stp, $msg='') {
- global $smd_um_event, $txp_permissions, $txp_user;
- $available_steps = array(
- 'smd_um' => false,
- 'smd_um_edit' => false,
- 'smd_um_save' => true,
- 'smd_um_save_new' => true,
- 'smd_um_groups' => false,
- 'smd_um_privs' => false,
- 'smd_um_prefs' => false,
- 'smd_um_multi_edit' => true,
- 'smd_um_change_pass' => true,
- 'smd_um_change_pass_form' => false,
- 'smd_um_change_pageby' => true,
- 'smd_um_table_install' => true,
- 'smd_um_table_remove' => true,
- 'save_pane_state' => true,
- );
- if (!has_privs($smd_um_event.'.usr.list')) {
- $stp = ($stp) ? $stp : 'smd_um_edit';
- $uid = safe_field('user_id', 'txp_users', "name='" . doSlash($txp_user) . "'");
- if ($uid) {
- // Inject this value so the edit step picks it up and edits only the current user.
- // The edit/save steps will verify if the current user is the one trying to be edited
- // to prevent people adding &user_id=N to the URL
- $_POST['user_id'] = $uid;
- }
- }
- if ($stp == 'save_pane_state') {
- smd_um_save_pane_state();
- } else if ($stp && bouncer($stp, $available_steps)) {
- if ($msg) {
- $stp($msg);
- } else {
- $stp();
- }
- } else {
- $smd_um_event($msg);
- }
- }
- // ------------------------
- // Try to hide the Admin->Users tab in the secondary nav via jQuery.
- // May fail with inventive DOM structures / themes
- // (note to self: campaign for improvement in this area because jQuery smells hackish)
- function smd_um_users_tab() {
- global $event;
- $userStr = gTxt('tab_site_admin');
- echo script_js(<<<EOJS
- jQuery(function() {
- jQuery("a[href='?event=admin']").each(function() {
- me = jQuery(this);
- if (me.text() == "{$userStr}") {
- me.parent().hide();
- }
- });
- if ('{$event}' == 'admin') {
- jQuery("a[href='?event=smd_um']").each(function() {
- me = jQuery(this);
- me.parent().removeClass('inactive').addClass('active'); // Hive, etc
- me.removeClass('tabdown').addClass('tabup'); // Classic, etc
- });
- }
- });
- EOJS
- );
- }
- // ------------------------
- function smd_um_welcome($evt, $stp) {
- $msg = '';
- switch ($stp) {
- case 'installed':
- smd_um_table_install(0);
- $msg = 'Super duper users!';
- break;
- case 'deleted':
- smd_um_table_remove(0);
- break;
- }
- return $msg;
- }
- // ------------------------
- // Main user display list
- function smd_um($msg='') {
- global $step, $smd_um_event, $txp_user, $smd_um_list_pageby;
- require_privs($smd_um_event.'.usr.list');
- $smd_um_prefs = smd_um_get_prefs();
- if (!smd_um_table_exist(1)) {
- smd_um_table_install(0);
- }
- pagetop(gTxt('smd_um_tab_name').' » '.gTxt('smd_um_usr_lbl'), $msg);
- extract(gpsa(array('page', 'sort', 'dir', 'crit', 'search_method')));
- if ($sort === '') $sort = get_pref('smd_um_sort_column', 'login');
- if ($dir === '') $dir = get_pref('smd_um_sort_dir', 'desc');
- $dir = ($dir == 'asc') ? 'asc' : 'desc';
- switch ($sort) {
- case 'real_name':
- $sort_sql = 'RealName '.$dir.', last_access desc';
- break;
- case 'email':
- $sort_sql = 'email '.$dir.', last_access desc';
- break;
- case 'privs':
- $sort_sql = 'privs '.$dir.', last_access desc';
- break;
- case 'article_count':
- $sort_sql = 'article_count '.$dir.', last_access desc';
- break;
- case 'image_count':
- $sort_sql = 'image_count '.$dir.', last_access desc';
- break;
- case 'file_count':
- $sort_sql = 'file_count '.$dir.', last_access desc';
- break;
- case 'link_count':
- $sort_sql = 'link_count '.$dir.', last_access desc';
- break;
- case 'last_login':
- $sort_sql = 'last_access '.$dir;
- break;
- default:
- $sort = 'name';
- $sort_sql = 'name '.$dir.', last_access desc';
- break;
- }
- set_pref('smd_um_sort_column', $sort, 'smd_um', PREF_HIDDEN, '', 0, PREF_PRIVATE);
- set_pref('smd_um_sort_dir', $dir, 'smd_um', PREF_HIDDEN, '', 0, PREF_PRIVATE);
- $switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
- $criteria = 1;
- $count_columns = array('article_count', 'image_count', 'file_count', 'link_count');
- if ($search_method and $crit != '') {
- $crit_escaped = doSlash(str_replace(array('\\','%','_','\''), array('\\\\','\\%','\\_', '\\\''), $crit));
- // Permit searching by privilege name (sort of)
- if ($search_method == 'privileges' && !is_numeric($crit_escaped)) {
- $levels = get_groups();
- foreach ($levels as $idx => $group) {
- if (strpos(strtolower($group), strtolower($crit_escaped)) !== false) {
- $crit_escaped = $idx;
- break;
- }
- }
- }
- // Permit <, =, and > operators in count searches.
- // nullcheck is not required for privs searches because the value is a true 0 (whereas in the computed
- // columns it's empty/null)
- $operator = '=';
- $nullcheck = '';
- if (in_array($search_method, $count_columns) || $search_method == 'privileges') {
- preg_match('/([<=>]+)?([0-9]+)/', $crit_escaped, $matches);
- $operator = (isset($matches[1]) && $matches[1] != '') ? $matches[1] : '=';
- $crit_escaped = (isset($matches[2]) && $matches[2] != '') ? $matches[2] : $crit_escaped;
- $char_one = substr($operator, 0, 1);
- $char_two = substr($operator, 1, 1);
- $nullcheck = ($char_one == '<' || ($char_one == '>' && $char_two == '=' && $crit_escaped == '0')) ? ' OR ISNULL('.$search_method.')' : '';
- }
- $critsql = array(
- 'login_name' => "name like '%$crit_escaped%'",
- 'real_name' => "RealName like '%$crit_escaped%'",
- 'email' => "email like '%$crit_escaped%'",
- 'privileges' => "privs $operator '$crit_escaped'",
- 'article_count' => "article_count $operator '$crit_escaped'$nullcheck",
- 'image_count' => "image_count $operator '$crit_escaped'$nullcheck",
- 'file_count' => "file_count $operator '$crit_escaped'$nullcheck",
- 'link_count' => "link_count $operator '$crit_escaped'$nullcheck",
- );
- if (array_key_exists($search_method, $critsql)) {
- $criteria = $critsql[$search_method];
- $limit = get_pref('smd_um_max_search_limit', $smd_um_prefs['smd_um_max_search_limit']['default']);
- } else {
- $search_method = '';
- $crit = '';
- }
- } else {
- $search_method = '';
- $crit = '';
- }
- // Since the *_count columns are computed we need to some jiggery pokery here.
- // Thus, if we're looking for counts of 'zero' the actual search value should be isnull()
- if (in_array($search_method, $count_columns) && $operator == '=' && $crit_escaped == '0') {
- $criteria = "ISNULL($search_method)";
- }
- // The fields, joins and sub-queries that make up the real and computed columns
- $fields = 'txu.user_id, txu.name, txu.RealName, txu.email, txu.privs, unix_timestamp(txu.last_access) as last_login, txp.total AS article_count, txi.total AS image_count, txf.total AS file_count, txl.total AS link_count';
- $clause = ' FROM '.PFX.'txp_users as txu
- LEFT JOIN (SELECT AuthorID, count(ID) AS total FROM '.PFX.'textpattern GROUP BY AuthorID) AS txp ON txp.AuthorID = txu.name
- LEFT JOIN (SELECT author, count(id) AS total FROM '.PFX.'txp_image GROUP BY author) AS txi ON txi.author = txu.name
- LEFT JOIN (SELECT author, count(id) AS total FROM '.PFX.'txp_file GROUP BY author) AS txf ON txf.author = txu.name
- LEFT JOIN (SELECT author, count(id) AS total FROM '.PFX.'txp_link GROUP BY author) AS txl ON txl.author = txu.name';
- // Perform a count on the relevant search item. Doing a count(*) is awkward due to the computed columns
- // so a straight query is performed with a loop to increment the total. getThing() or getRows for some reason
- // failed under certain conditions
- $total = 0;
- // Call this so plugins that hook into the step can play
- $criteria .= callback_event('admin_criteria', 'author_list', 0, $criteria);
- $totrs = safe_query('SELECT '.$fields.$clause.' HAVING '.$criteria);
- while ($row = nextRow($totrs)) {
- $total++;
- }
- $btnbar = smd_um_buttons('usr');
- echo '<h1 class="txp-heading">', gTxt('smd_um_heading_usr'), '</h1>',
- '<div id="', $smd_um_event, '_control" class="txp-control-panel">',
- $btnbar;
- if ($total < 1) {
- if ($criteria != 1) {
- echo n, smd_um_search_form($crit, $search_method),
- n, graf(gTxt('no_results_found'), ' class="indicator"'),
- n, '</div>';
- }
- return;
- }
- $limit = max($smd_um_list_pageby, 15);
- list($page, $offset, $numPages) = pager($total, $limit, $page);
- $use_multi_edit = ( has_privs($smd_um_event.'.usr.edit') && (safe_count('txp_users', '1=1') > 1) );
- echo n, smd_um_search_form($crit, $search_method), '</div>';
- // Retrieve the user info and related counts
- $rs = safe_query('SELECT '.$fields.$clause.' HAVING '.$criteria.' ORDER BY '.$sort_sql.' LIMIT '.$offset.', '.$limit);
- if ($rs) {
- echo n, '<div class="txp-container">',
- n, '<form action="index.php" id="smd_um_form" method="post" name="longform" class="multi_edit_form" onsubmit="return verify(\''.gTxt('are_you_sure').'\')">',
- n, '<div class="txp-listtables">',
- n, startTable('', '', 'txp-list'),
- n, '<thead>',
- n, tr(
- n. (($use_multi_edit)
- ? hCell(fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), '', ' title="'.gTxt('toggle_all_selected').'" class="multi-edit"')
- : hCell('', '', ' class="multi-edit"')
- ).
- n. column_head('login_name', 'name', 'smd_um', true, $switch_dir, $crit, $search_method, (('name' == $sort) ? "$dir " : '').'name login-name').
- n. column_head('real_name', 'real_name', 'smd_um', true, $switch_dir, $crit, $search_method, (('real_name' == $sort) ? "$dir " : '').'name real-name').
- n. column_head('email', 'email', 'smd_um', true, $switch_dir, $crit, $search_method, (('email' == $sort) ? "$dir " : '').'email').
- n. column_head('privileges', 'privs', 'smd_um', true, $switch_dir, $crit, $search_method, (('privs' == $sort) ? "$dir " : '').'privs').
- n. column_head('last_login', 'last_login', 'smd_um', true, $switch_dir, $crit, $search_method, (('last_login' == $sort) ? "$dir " : '').'date last-login modified').
- n. column_head(gTxt('smd_um_article_count'), 'article_count', 'smd_um', true, $switch_dir, $crit, $search_method, (('article_count' == $sort) ? "$dir " : '')).
- n. column_head(gTxt('smd_um_image_count'), 'image_count', 'smd_um', true, $switch_dir, $crit, $search_method, (('image_count' == $sort) ? "$dir " : '')).
- n. column_head(gTxt('smd_um_file_count'), 'file_count', 'smd_um', true, $switch_dir, $crit, $search_method, (('file_count' == $sort) ? "$dir " : '')).
- n. column_head(gTxt('smd_um_link_count'), 'link_count', 'smd_um', true, $switch_dir, $crit, $search_method, (('link_count' == $sort) ? "$dir " : ''))
- ),
- n, '</thead>',
- n, '<tbody>';
- $curr_priv = safe_field('privs', 'txp_users', "name = '" .doSlash($txp_user). "'");
- while ($row = nextRow($rs)) {
- extract(doSpecial($row));
- $permitted = smd_um_can_edit($curr_priv, $name, $privs);
- echo tr(
- td(((has_privs($smd_um_event.'.usr.edit') && $txp_user != $row['name']) ? fInput('checkbox', 'selected[]', $row['name'], 'checkbox') : ''), '', 'multi-edit').
- td( (($permitted) ? eLink($smd_um_event, 'smd_um_edit', 'user_id', $user_id, $name) : $name), '', 'name login-name actions').
- td($RealName, '', 'name real-name').
- td('<a href="mailto:'.$email.'">'.$email.'</a>', '', 'email').
- td(smd_um_get_priv_level($privs), '', 'privs').
- td(($last_login ? safe_strftime('%b %Y', $last_login) : ''), '', 'date last-login modified').
- td(($article_count) ? eLink('list', 'list', 'search_method', 'author', $article_count, 'crit', $name) : '0').
- td(($image_count) ? eLink('image', 'image_list', 'search_method', 'author', $image_count, 'crit', $name) : '0').
- td(($file_count) ? eLink('file', 'file_list', 'search_method', 'author', $file_count, 'crit', $name) : '0').
- td(($link_count) ? eLink('link', 'link_edit', 'search_method', 'author', $link_count, 'crit', $name) : '0')
- );
- }
- echo n, '</tbody>',
- n, endTable(),
- n, '</div>',
- n, (($use_multi_edit) ? smd_um_multiedit_form($page, $sort, $dir, $crit, $search_method) : ''),
- n, tInput(),
- n, '</form>',
- n, '<div id="users_navigation" class="txp-navigation">',
- n, nav_form('smd_um', $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit),
- n, pageby_form('smd_um', $smd_um_list_pageby),
- n, '</div>',
- n, smd_um_active_users(),
- n, '</div>';
- }
- // Call the Admin side's author_list routine so other plugins with a vested interest can join the party
- callback_event('admin', 'author_list');
- }
- // Can this logged-in user edit the given user account?
- function smd_um_can_edit($curr_priv, $name, $privs) {
- global $smd_um_event, $txp_user;
- $smd_um_prefs = smd_um_get_prefs();
- $permitted = false; // Assume no editing rights unlesss otherwise stated
- $tiered = get_pref('smd_um_hierarchical_groups', $smd_um_prefs['smd_um_hierarchical_groups']['default']);
- $protected = get_pref('smd_um_admin_group', $smd_um_prefs['smd_um_admin_group']['default']);
- // For some reason checking ($privs != '') doesn't work *shrug*
- if ( ($name != '') && ($privs == 0 || $privs) ) {
- $permitted = has_privs($smd_um_event.'.usr.edit.own') && ($name == $txp_user);
- $can_edit = has_privs($smd_um_event.'.usr.edit');
- if ($can_edit) {
- $permitted |= $can_edit;
- if ($tiered) {
- $permitted &= (($privs >= $curr_priv) || ($privs == 0));
- }
- if ($protected) {
- $permitted &= (($privs != $protected) || ($curr_priv == $protected));
- }
- }
- }
- return $permitted;
- }
- // ------------------------
- // Edit a single User
- function smd_um_edit($msg='') {
- global $step, $txp_user, $smd_um_event;
- $vars = array('user_id', 'name', 'RealName', 'email', 'privs');
- extract(gpsa($vars));
- $rs = array();
- $curr_priv = safe_field('privs', 'txp_users', "name = '" .doSlash($txp_user). "'");
- if ($user_id) {
- $user_id = assert_int($user_id);
- $rs = safe_row('*', 'txp_users', "user_id = $user_id");
- extract($rs);
- } else if (!has_privs($smd_um_event.'.usr.create')) {
- // If the current user doesn't have sufficient rights to create new users
- // then this Edit request without user_id is a self-edit
- $rs = safe_row('*', 'txp_users', "name = '" .doSlash($txp_user). "'");
- extract($rs);
- }
- // Check for edit / creation rights
- $permitted = ($user_id) ? smd_um_can_edit($curr_priv, $name, $privs) : has_privs($smd_um_event.'.usr.create');
- if (!$permitted)
- exit(pageTop('Restricted').'<p style="margin-top:3em;text-align:center">'.
- gTxt('restricted_area').'</p>');
- $caption = gTxt(($user_id) ? 'edit_author' : 'add_new_author');
- pagetop(gTxt('smd_um_tab_name').' » '.gTxt('smd_um_usr_lbl'), $msg);
- $btnbar = smd_um_buttons('usr');
- echo '<h1 class="txp-heading">', $caption, '</h1>',
- n, '<div id="', $smd_um_event, '_control" class="txp-control-panel">',
- n, $btnbar,
- n, '</div>',
- n, '<div id="', $smd_um_event.'_container" class="txp-edit">',
- n, form(
- '<div class="txp-edit">'.n.
- inputLabel('login_name', ($user_id ? strong($name) : fInput('text', 'name', $name, '', '', '', INPUT_REGULAR, '', 'login_name')), ($user_id ? '' : 'login_name'), ($user_id ? '' : 'add_new_author')).n.
- inputLabel('real_name', fInput('text', 'RealName', $RealName, '', '', '', INPUT_REGULAR, '', 'real_name'), 'real_name').n.
- inputLabel('login_email', fInput('text', 'email', $email, '', '', '', INPUT_REGULAR, '', 'login_email'), 'email').n.
- inputLabel('privileges', (($txp_user != $name) ? selectInput('privs', smd_um_get_groups(1), $privs) : hInput('privs', $privs).strong(smd_um_get_priv_level($privs))), ($user_id ? '' : 'privileges'), 'about_privileges').n.
- pluggable_ui('author_ui', 'extend_detail_form', '', $rs).n.
- graf(fInput('submit', '', gTxt('save'), 'publish')).
- eInput($smd_um_event).
- ($user_id ? hInput('user_id', $user_id).sInput('smd_um_save') : sInput('smd_um_save_new')).
- '</div>'
- , '', '', 'post', 'edit-form', '', 'user_edit'),
- '</div>';
- // Call the Admin side's author_edit routine so other plugins with a vested interest can join the party
- callback_event('admin', 'author_edit');
- }
- // ------------------------
- // Virtually cloned from Admin->Users
- function smd_um_save() {
- global $event, $smd_um_event, $txp_user;
- // Call the Admin side's author_save routine so other plugins can join the party
- callback_event('admin', 'author_save');
- extract(doSlash(psa(array('privs', 'user_id', 'RealName', 'email'))));
- $privs = assert_int($privs);
- $user_id = assert_int($user_id);
- $name = safe_field('name', 'txp_users', "user_id = $user_id");
- $curr_priv = safe_field('privs', 'txp_users', "name = '" .doSlash($txp_user). "'");
- // Check for hacking attempts
- $permitted = smd_um_can_edit($curr_priv, $name, $privs);
- if (!$permitted)
- exit(pageTop('Restricted').'<p style="margin-top:3em;text-align:center">'.
- gTxt('restricted_area').'</p>');
- if (!is_valid_email($email)) {
- smd_um_edit(array(gTxt('email_required'), E_ERROR));
- return;
- }
- $rs = safe_update('txp_users', "
- privs = $privs,
- RealName = '$RealName',
- email = '$email'",
- "user_id = $user_id"
- );
- if ($rs) {
- $msg = gTxt('author_updated', array('{name}' => $RealName));
- } else {
- $msg = '';
- }
- smd_um_dispatcher($event, '', $msg);
- }
- // ------------------------
- // Virtually cloned from Admin->Users
- function smd_um_save_new() {
- global $smd_um_event;
- require_privs($smd_um_event.'.usr.create');
- // Call the Admin side's author_save_new routine so other plugins with a vested interest can join the party
- callback_event('admin', 'author_save_new');
- extract(doSlash(psa(array('privs', 'name', 'email', 'RealName'))));
- $smd_um_prefs = smd_um_get_prefs();
- $privs = assert_int($privs);
- $length = function_exists('mb_strlen') ? mb_strlen($name, '8bit') : strlen($name);
- if ($name and $length <= 64 and is_valid_email($email)) {
- $exists = safe_field('name', 'txp_users', "name = '" .$name. "'");
- if ($exists) {
- smd_um_edit(array(gTxt('author_already_exists', array('{name}' => $name)), E_ERROR));
- return;
- }
- $pass_len = get_pref('smd_um_pass_length', $smd_um_prefs['smd_um_pass_length']['default']);
- $password = generate_password($pass_len);
- $hash = doSlash(txp_hash_password($password));
- $nonce = doSlash(md5(uniqid(mt_rand(), TRUE)));
- $rs = safe_insert('txp_users', "
- privs = $privs,
- name = '$name',
- email = '$email',
- RealName = '$RealName',
- nonce = '$nonce',
- pass = '$hash'
- ");
- if ($rs) {
- // TODO: consider cloning send_password() because only people with admin.edit can run it (i.e. Publishers)
- send_password($RealName, $name, $email, $password);
- $msg = gTxt('password_sent_to').sp.$email;
- $smd_um_event($msg);
- } else {
- $msg = array(gTxt('error_adding_new_author'), E_ERROR);
- smd_um_edit($msg);
- }
- } else {
- $msg = array(gTxt('error_adding_new_author'), E_ERROR);
- smd_um_edit($msg);
- }
- }
- // ------------------------
- // Group management panel
- function smd_um_groups($msg='') {
- global $smd_um_event, $txp_user, $txp_groups, $txp_permissions;
- require_privs($smd_um_event.'.grp');
- if (!smd_um_table_exist()) {
- smd_um_table_install(0);
- }
- // Handle any form actions
- if (ps('smd_um_group_save')) {
- $excluded = smd_um_get_groups(0);
- $ids = ps('smd_um_group_id');
- $names = ps('smd_um_group_name');
- $titles = ps('smd_um_group_title');
- foreach($ids as $idx => $id) {
- $title = $titles[$idx];
- $name = strtolower(sanitizeForUrl($names[$idx]));
- // Can't create duplicate types
- if (!in_array($name, $excluded)) {
- safe_update(SMD_UM_GROUPS, "name='" . doSlash($name) . "'", "id='" . doSlash($id) . "'");
- }
- smd_um_upsert_lang($title, $name);
- }
- $msg = gTxt('smd_um_grp_saved');
- } else if (ps('smd_um_group_add')) {
- $title = ps('smd_um_new_grp');
- $name = ps('smd_um_new_grp_name');
- $name = ($name == '') ? strtolower(sanitizeForUrl($title)) : $name;
- if ($name) {
- $exists = safe_field('id', SMD_UM_GROUPS, "name='".doSlash($name)."'");
- if ($exists) {
- $msg = array(gTxt('smd_um_grp_exists', array('{id}' => $exists)), E_USER_WARNING);
- } else {
- // It's not atomic but it'll do, given that:
- // a) normally only one person administers this plugin
- // b) groups are added one at a time
- $curr_max = safe_field("MAX(id)", SMD_UM_GROUPS, '1=1');
- $new_priv = ($curr_max + 1);
- safe_insert(SMD_UM_GROUPS, "id='" . $new_priv . "', name='" . doSlash($name) . "'");
- smd_um_upsert_lang($title, $name);
- $based_on = ps('smd_um_new_grp_based_on');
- if ($based_on != '') {
- assert_int($based_on);
- // Can't rely on the privs being in the database so resort to the (merged) array
- foreach ($txp_permissions as $area => $privs) {
- $privs = do_list($privs);
- if (in_array($based_on, $privs)) {
- safe_insert(SMD_UM_PRIVS, "area='" . doSlash($area) . "', priv='" . doSlash($new_priv) . "'");
- }
- }
- }
- $msg = gTxt('smd_um_grp_created', array('{name}' => $name));
- }
- } else {
- $msg = array(gTxt('smd_um_name_required'), E_ERROR);
- }
- } else if (ps('smd_um_group_del')) {
- $id = str_replace('smd_um_del_', '', ps('smd_um_grp_del'));
- assert_int($id);
- $affected_users = safe_column('user_id', 'txp_users', "privs = '".doSlash($id)."'");
- if ($affected_users) {
- // Set all orphaned users to no privs -- can always assign them a new group from the main screen later
- $ret = safe_update('txp_users', "privs=0", "user_id IN ('". join("','", doSlash($affected_users)) ."')");
- }
- // TODO: double check this isn't a core group?
- $red = safe_delete(SMD_UM_GROUPS, "id='".doSlash($id)."'");
- if ($red) {
- $ret = safe_delete(SMD_UM_PRIVS, "priv='".doSlash($id)."'");
- $msg = gTxt('smd_um_grp_deleted') . ($affected_users ? gTxt('smd_um_grp_affected', array('{num}' => count($affected_users))) : '');
- }
- }
- // Render the page
- pagetop(gTxt('smd_um_tab_name').' » '.gTxt('smd_um_grp_lbl'), $msg);
- $btnbar = smd_um_buttons('grp');
- $grouplist = smd_um_get_groups(1);
- unset($grouplist[0]); // Don't want None privs
- $grouplist = selectInput('smd_um_new_grp_based_on', $grouplist, '', true, '', 'smd_um_new_grp_based_on');
- // New group
- echo '<h1 class="txp-heading">', gTxt('smd_um_heading_grp'), '</h1>',
- n, '<div id="'.$smd_um_event.'_control" class="txp-control-panel">',
- n, $btnbar,
- n, form(
- graf(
- '<label for="smd_um_new_grp">' . gTxt('smd_um_grp_new') . '</label>'
- .n.fInput('text', 'smd_um_new_grp', '', '', '', '', '', '', 'smd_um_new_grp')
- .n.'<label for="smd_um_new_grp_name">' . gTxt('smd_um_grp_new_name') . '</label>'
- .n.fInput('text', 'smd_um_new_grp_name', '', '', '', '', '', '', 'smd_um_new_grp_name')
- .n.'<label for="smd_um_new_grp_based_on">' . gTxt('smd_um_based_on') . '</label>'
- .n.$grouplist
- .n.fInput('submit', 'smd_um_group_add', gTxt('create'))
- .n.eInput($smd_um_event)
- .n.sInput('smd_um_groups')
- )
- , '','','post','search-form'
- ),
- n, '</div>';
- // Retrieve the group info and user counts per privilege level
- $fields = 'smdg.id, smdg.name, smdg.core, txu.total AS user_count';
- $clause = ' FROM '.PFX.'smd_um_groups AS smdg
- LEFT JOIN (SELECT privs, count(privs) AS total FROM '.PFX.'txp_users GROUP BY privs) AS txu ON smdg.id = txu.privs';
- $rs = getRows('SELECT ' . $fields.$clause . ' ORDER BY id');
- if ($rs) {
- echo n, '<div class="plugin-column">',
- n, '<form action="index.php" id="smd_um_grp_form" method="post" name="longform" onsubmit="return verify(\''.gTxt('are_you_sure').'\')">',
- n.'<div class="txp-listtables">'.
- n, startTable('', '', 'txp-list'),
- n, '<thead>',
- n, tr(
- hCell('ID', '', ' class="id"').
- hCell('name', '', ' class="name"').
- hCell('title', '', ' class="name"').
- hCell('', '', '')
- ),
- n, '</thead>',
- n, '<tbody>';
- foreach ($rs as $row) {
- extract(doSpecial($row));
- $user_count = empty($user_count) ? 0 : $user_count;
- $dLink = ($core) ? ' ' : fInput('submit', 'smd_um_group_del', "Ă", '', '', 'smd_um_presub(this)', '', '', 'smd_um_del_'.$id)
- .eInput($smd_um_event)
- .sInput('smd_um_groups')
- .tInput();
- echo tr(
- tda(
- hInput('smd_um_group_id[]', $id)
- .(($user_count) ? eLink($smd_um_event, '', 'search_method', 'privileges', $id, 'crit', $id) : $id)
- , ' class="id"'
- .(($user_count) ? ' title="' . gTxt('smd_um_user_count') . $user_count . '"': '')
- )
- .td(fInput('text', 'smd_um_group_name[]', $name), '', 'name')
- .td(fInput('text', 'smd_um_group_title[]', gTxt($name)), '', 'name')
- .td($dLink)
- );
- }
- echo n, '</tbody>',
- n, endTable(),
- n, '</div>',
- n, graf(fInput('submit', 'smd_um_group_save', gTxt('save'), 'publish')),
- n, fInput('hidden', 'smd_um_grp_del', '', '', '', '', '', '', 'smd_um_grp_del'),
- n, eInput($smd_um_event),
- n, sInput('smd_um_groups'),
- n, tInput(),
- n, '</form>',
- n, smd_um_active_users(),
- n, '</div>',
- script_js(<<<EOJS
- function smd_um_presub(obj) {
- jQuery('#smd_um_grp_del').val(jQuery(obj).attr('id'));
- }
- EOJS
- );
- }
- }
- // ------------------------
- // Privs management panel
- function smd_um_privs($msg='') {
- global $smd_um_event, $txp_user, $txp_permissions;
- require_privs($smd_um_event.'.prv');
- if (!smd_um_table_exist()) {
- smd_um_table_install(0);
- }
- if (ps('smd_um_priv_save')) {
- $areas = ps('smd_um_areas');
- foreach ($areas as $area) {
- $ar_fakename = str_replace('.', '---', $area);
- $privs = ps($ar_fakename);
- $area = strtolower(sanitizeForPage($area));
- // Delete the old area privs if they exist
- safe_delete(SMD_UM_PRIVS, "area='".doSlash($area)."'");
- if (is_array($privs)) {
- foreach ($privs as $priv) {
- // Reset should always be first in the list since it's the first checkbox col
- // If reset, don't add the privs again (thus they will be read from admin_config.php)
- if ($priv == 'smd_um_reset') {
- break;
- } else {
- assert_int($priv);
- safe_insert(SMD_UM_PRIVS, "area='" . doSlash($area) . "', priv='" . doSlash($priv) . "'");
- }
- }
- }
- }
- // Merge the changes into the priv table
- smd_um_priv_merge(0,1);
- $msg = gTxt('smd_um_prv_saved');
- } else if (ps('smd_um_priv_add')) {
- $name = ps('smd_um_new_prv');
- $name = strtolower(sanitizeForPage($name));
- if ($name) {
- if (strpos($name, 'smd_um') === 0) {
- // Can't create privs for this plugin
- $msg = array(gTxt('smd_um_prv_smd_um'), E_USER_WARNING);
- } else {
- $exists = array_key_exists($name, $txp_permissions);
- if ($exists) {
- $msg = array(gTxt('smd_um_prv_exists'), E_USER_WARNING);
- } else {
- safe_insert(SMD_UM_PRIVS, "area='" . doSlash($name) . "'");
- smd_um_priv_merge(0,1);
- $msg = gTxt('smd_um_prv_created', array('{area}' => $name));
- }
- }
- } else {
- $msg = array(gTxt('smd_um_name_required'), E_ERROR);
- }
- }
- pagetop(gTxt('smd_um_tab_name').' » '.gTxt('smd_um_prv_lbl'), $msg);
- $btnbar = smd_um_buttons('prv');
- echo '<h1 class="txp-heading">', gTxt('smd_um_heading_prv'), '</h1>',
- n, '<div id="'.$smd_um_event.'_control" class="txp-control-panel">',
- n, $btnbar,
- n, form(
- graf(
- '<label for="smd_um_new_prv">' . gTxt('smd_um_prv_new') . '</label>'
- .n.fInput('text', 'smd_um_new_prv', '', '', '', '', '', '', 'smd_um_new_prv')
- .n.fInput('submit', 'smd_um_priv_add', gTxt('create'))
- .n.eInput($smd_um_event)
- .n.sInput('smd_um_privs')
- )
- , '','','post','search-form'
- ),
- n, '</div>';
- $grouplist_name = smd_um_get_groups(0);
- $grouplist_title = smd_um_get_groups(1);
- unset($grouplist_name[0]); // Don't want None privs
- unset($grouplist_title[0]); // Ditto
- $curr_area = '';
- $area_count = 0;
- $thatts = ' class="smd_um_grp_name" title="' . gTxt('smd_um_sel_grp') . '"';
- $headers = '<thead>'.tr(
- hCell('', '', ' class="smd_um_sel_area" title="' . gTxt('smd_um_sel_all') . '"')
- .hCell(gTxt('smd_um_reset'), '', ' class="smd_um_reset_col" title="' . gTxt('smd_um_sel_reset') . '"')
- .hCell(join('</th><th'.$thatts.'>', $grouplist_title), '', $thatts)
- , ' class="smd_um_prv_hdr"'). '</thead>';
- $viz = do_list(get_pref('pane_smd_um_priv_visible'));
- echo script_js(<<<EOJS
- function smd_um_presub(obj) {
- jQuery('#smd_um_prv_del').val(jQuery(obj).attr('id'));
- }
- jQuery.fn.smd_um_rowsel = function(idx) {
- return jQuery('tr:nth-child('+(idx+1)+') td.smd_um_checkbox', this);
- }
- jQuery.fn.smd_um_colsel = function(idx) {
- return jQuery('tr td:nth-child('+(idx+1)+')', this);
- }
- // Affect all highlighted checkboxes on keypress
- function smd_um_toggleCheckbox(ev) {
- key = ev.keyCode;
- obj = jQuery('.smd_um_selected :checkbox');
- switch(key) {
- case 67:
- // (c)heck selected boxes
- obj.prop('checked', true);
- break;
- case 68:
- // (d)eselect all selected rows/cols
- jQuery('.smd_um_selected, .smd_um_rsel, .smd_um_csel').removeClass('smd_um_selected smd_um_rsel smd_um_csel');
- break;
- case 84:
- // (t)oggle selected boxes
- obj.each(function() {
- cb = jQuery(this);
- if (cb.prop('checked') == true) {
- cb.prop('checked', false);
- } else {
- cb.prop('checked', true);
- }
- });
- break;
- case 85:
- // (u)ncheck selected boxes
- obj.prop('checked', false);
- break;
- }
- }
- jQuery(function() {
- jQuery(document).bind('keyup', smd_um_toggleCheckbox);
- // Row selector
- jQuery('.smd_um_prv_name').click(function() {
- tr = jQuery(this).closest('tr');
- rownum = tr.index();
- obj = jQuery(tr).parent().smd_um_rowsel(rownum);
- // Can't use toggleClass because it would untoggle any cols that were already selected
- if (jQuery(this).hasClass('smd_um_rsel')) {
- obj.removeClass('smd_um_selected');
- } else {
- obj.addClass('smd_um_selected');
- }
- jQuery(this).toggleClass('smd_um_rsel');
- });
- // Column selector
- jQuery('.smd_um_grp_name, .smd_um_reset_col').click(function() {
- colnum = jQuery(this).index();
- tbody = jQuery(this).parent().parent().next('tbody');
- obj = jQuery(tbody).smd_um_colsel(colnum);
- // Can't use toggleClass because it would untoggle any rows that were already selected
- if (colnum > 0) {
- if (jQuery(this).hasClass('smd_um_csel')) {
- obj.removeClass('smd_um_selected');
- } else {
- obj.addClass('smd_um_selected');
- }
- }
- jQuery(this).toggleClass('smd_um_csel');
- });
- // Whole table selector
- jQuery('.smd_um_sel_area').click(function() {
- me = jQuery(this);
- thead = me.parent().parent();
- tbody = thead.next('tbody');
- tbody.toggleClass('smd_um_allsel');
- if (tbody.hasClass('smd_um_allsel')) {
- tbody.find('.smd_um_prv_name').removeClass('smd_um_rsel').click();
- me.nextAll('.smd_um_grp_name').addClass('smd_um_csel');
- } else {
- tbody.find('.smd_um_prv_name').addClass('smd_um_rsel').click();
- me.nextAll('.smd_um_grp_name').removeClass('smd_um_csel');
- }
- });
- });
- EOJS
- );
- echo n, '<div class="txp-list">',
- n, '<form action="index.php" id="smd_um_privilege_form" method="post" name="longform" onsubmit="return verify(\''.gTxt('are_you_sure').'\')">',
- n, eInput($smd_um_event).sInput('smd_um_privs').tInput();
- foreach ($txp_permissions as $area => $privs) {
- $priv_list = do_list($privs);
- $area_parts = do_list($area, '.');
- if (preg_match('/^([A-Za-z0-9]{3,3})\_/', $area_parts[0], $matches)) {
- // Plugin
- $area_parts[0] = $matches[1];
- }
- // Start of a new area so close the previous one and start a new block
- if ($curr_area != $area_parts[0]) {
- if ($area_count > 0) {
- echo '</tbody>' . endTable() . '</div></div>';
- }
- $area_head = gTxt($area_parts[0]);
- $is_viz = in_array($area_parts[0], $viz);
- $ref = 'smd_um_priv_'.$area_parts[0];
- echo n, '<div class="smd_um_privgroup"><h3 class="txp-summary lever', ($is_viz ? ' expanded' : ''), '"><a href="#', $ref, '">', $area_parts[0], (($area_parts[0] != $area_head) ? ' ('. gTxt($area_parts[0]). ')' : ''), '</a></h3>',
- n, '<div id="', $ref, '" class="toggle" style="display:', ($is_viz ? 'block' : 'none'), '">',
- n, fInput('submit', 'smd_um_priv_save', gTxt('save'), 'smd_um_privsave'),
- n, startTable('', '', 'txp-list'),
- n, $headers,
- n, '<tbody>';
- }
- $privboxes = array();
- $safe_area = str_replace('.', '---', $area).'[]';
- foreach ($grouplist_name as $id => $priv) {
- /// Dots aren't valid characters for a name so replace them now and swap them back upon Save
- $privboxes[] = td(checkbox($safe_area, $id, (in_array($id, $priv_list))), '', 'smd_um_checkbox');
- }
- echo tr(
- tda($area.hInput('smd_um_areas[]', $area), ' class="smd_um_prv_name" title="' . gTxt('smd_um_sel_prv') . '"')
- .td(checkbox($safe_area, 'smd_um_reset', 0), '', 'smd_um_resetbox')
- .join(n, $privboxes)
- );
- $curr_area = $area_parts[0];
- $area_count++;
- }
- echo n, endTable(),
- n, '</div></div>',
- n, fInput('hidden', 'smd_um_prv_del', '', '', '', '', '', '', 'smd_um_prv_del'),
- n, '</form>',
- n, smd_um_active_users(),
- n, '</div>';
- }
- // -------------------------------------------------------------
- function smd_um_wrap_widget($widget) {
- return '<span class="edit-value">'.$widget.'</span>';
- }
- // ------------------------
- // Prefs management panel
- function smd_um_prefs($msg='') {
- global $smd_um_event, $txp_user;
- require_privs($smd_um_event.'.prf');
- if (!smd_um_table_exist()) {
- smd_um_table_install(0);
- }
- $smd_um_prefs = smd_um_get_prefs();
- if (ps('smd_um_pref_save')) {
- foreach ($smd_um_prefs as $idx => $prefobj) {
- $val = ps($idx);
- $val = (is_array($val)) ? join(', ', $val) : $val;
- set_pref($idx, doSlash($val), $smd_um_event, $prefobj['type'], $prefobj['html'], $prefobj['position']);
- }
- $msg = gTxt('preferences_saved');
- }
- pagetop(gTxt('smd_um_tab_name').' » '.gTxt('smd_um_prf_lbl'), $msg);
- $btnbar = smd_um_buttons('prf');
- echo '<h1 class="txp-heading">', gTxt('smd_um_heading_prf'), '</h1>',
- n, '<div id="', $smd_um_event, '_control" class="txp-control-panel">', $btnbar, '</div>';
- $out = array();
- $out[] = n.'<div class="plugin-column">';
- $out[] = '<form name="smd_um_prefs" id="smd_um_prefs" action="index.php" method="post">';
- $out[] = eInput($smd_um_event).sInput('smd_um_prefs');
- $last_grp = '';
- foreach ($smd_um_prefs as $idx => $prefobj) {
- if ($last_grp != $prefobj['group']) {
- $out[] = hed(gTxt($prefobj['group']), 2);
- }
- $last_grp = $prefobj['group'];
- $subout = array();
- $label = '<span class="edit-label">'
- .'<label>'.gTxt($idx).'</label>'
- .'</span>';
- $val = get_pref($idx, $prefobj['default'], 1);
- $vis = (isset($prefobj['visible']) && !$prefobj['visible']) ? 'empty' : '';
- switch ($prefobj['html']) {
- case 'text_input':
- $subout[] = smd_um_wrap_widget(fInput('text', $idx, $val, '', '', '', INPUT_REGULAR, '', $idx));
- break;
- case 'textarea':
- $subout[] = text_area($idx, '', '', $val, $idx);
- break;
- case 'yesnoradio':
- $subout[] = smd_um_wrap_widget(yesnoRadio($idx, $val));
- break;
- case 'radioset':
- $subout[] = smd_um_wrap_widget(radioSet($prefobj['content'], $idx, $val));
- break;
- case 'checkboxset':
- $vals = do_list($val);
- $lclout = array();
- foreach ($prefobj['content'] as $cb => $val) {
- $checked = in_array($cb, $vals);
- $lclout[] = checkbox($idx.'[]', $cb, $checked). '<label>' . gTxt($val) . '</label>';
- }
- $subout[] = smd_um_wrap_widget(join(n, $lclout));
- break;
- case 'selectlist':
- $subout[] = smd_um_wrap_widget(selectInput($idx, $prefobj['content'][0], $val, $prefobj['content'][1]));
- break;
- default:
- if ( strpos($prefobj['html'], 'smd_um_') !== false && is_callable($prefobj['html']) ) {
- $subout[] = smd_um_wrap_widget($prefobj['html']($idx, $val));
- }
- break;
- }
- $out[] = graf($label . n.join(n ,$subout), ($vis ? ' class="'.$vis.'"' : ''));
- }
- $out[] = graf(fInput('submit', 'smd_um_pref_save', gTxt('save'), 'publish'));
- $out[] = tInput();
- $out[] = '</form>'.smd_um_active_users().'</div>';
- echo join(n, $out);
- }
- // ------------------------
- // Common buttons for the interface
- function smd_um_buttons($curr='usr') {
- global $step, $smd_um_event;
- $grp = has_privs($smd_um_event.'.grp');
- $prf = has_privs($smd_um_event.'.prf');
- $prv = has_privs($smd_um_event.'.prv');
- $new = has_privs($smd_um_event.'.usr.create');
- $usr = ($grp || $prf || $prv); // Don't show usr button if it's the only tab available
- $btns = array (
- 'new' => ( ($new) ? sLink($smd_um_event, 'smd_um_edit', gTxt('smd_um_new_user'), 'navlink') : ''),
- 'grp' => ( ($grp) ? sLink($smd_um_event, 'smd_um_groups', gTxt('smd_um_grp_lbl'), 'navlink') : ''),
- 'prf' => ( ($prf) ? sLink($smd_um_event, 'smd_um_prefs', gTxt('smd_um_prf_lbl'), 'navlink') : ''),
- 'prv' => ( ($prv) ? sLink($smd_um_event, 'smd_um_privs', gTxt('smd_um_prv_lbl'), 'navlink') : ''),
- 'usr' => ( ($usr) ? sLink($smd_um_event, 'smd_um_list', gTxt('smd_um_usr_lbl'), 'navlink') : ''),
- 'chp' => ( sLink($smd_um_event, 'smd_um_change_pass_form', gTxt('change_password'), 'navlink')),
- );
- return graf(
- (($curr == 'usr') ? n. ($step === 'smd_um_edit' ? '' : $btns['chp']) .n. $btns['new'] .n. strong($btns['usr']) : n.$btns['usr'])
- .n.(($curr == 'grp') ? strong($btns['grp']) : $btns['grp'])
- .n.(($curr == 'prv') ? strong($btns['prv']) : $btns['prv'])
- .n.(($curr == 'prf') ? strong($btns['prf']) : $btns['prf'])
- , ' class="txp-buttons"');
- }
- // ------------------------
- // Alter the pageby quantity
- function smd_um_change_pageby() {
- global $smd_um_event;
- event_change_pageby('smd_um');
- $smd_um_event();
- }
- // ------------------------
- // The user panel search dropdown list
- function smd_um_search_form($crit, $method) {
- global $smd_um_event;
- $methods = array(
- 'login_name' => gTxt('login_name'),
- 'real_name' => gTxt('real_name'),
- 'email' => gTxt('email'),
- 'privileges' => gTxt('privileges'),
- 'article_count' => gTxt('smd_um_article_count'),
- 'image_count' => gTxt('smd_um_image_count'),
- 'file_count' => gTxt('smd_um_file_count'),
- 'link_count' => gTxt('smd_um_link_count'),
- );
- return search_form($smd_um_event, '', $crit, $methods, $method, 'login');
- }
- // ------------------------
- function smd_um_get_priv_level($priv) {
- $levels = get_groups();
- return $levels[$priv];
- }
- // ------------------------
- // Merge/edit the groups & privs into the existing global arrays
- function smd_um_priv_merge($do_grp=1, $do_priv=1) {
- global $txp_groups, $txp_permissions;
- $smd_um_prefs = smd_um_get_prefs();
- if ($do_grp && smd_um_table_exist(SMD_UM_GROUPS)) {
- $new_groups = safe_rows('id, name', SMD_UM_GROUPS, '1=1');
- foreach ($new_groups as $row) {
- $txp_groups[$row['id']] = $row['name'];
- }
- ksort($txp_groups);
- }
- if ($do_priv && smd_um_table_exist(SMD_UM_PRIVS)) {
- $new_privs = safe_rows('area, GROUP_CONCAT(priv) AS privs', SMD_UM_PRIVS, '1=1 GROUP BY area ORDER BY area');
- // Allow this plugin's strings to be skipped if we don't want people upsetting the plugin's behaviour
- $self_edit = get_pref('smd_um_self_alter', $smd_um_prefs['smd_um_self_alter']['default']);
- foreach ($new_privs as $row) {
- if (strpos($row['area'], 'smd_um') === false || $self_edit) {
- $txp_permissions[$row['area']] = $row['privs'];
- }
- }
- ksort($txp_permissions);
- }
- }
- // ------------------------
- // Show who's currently online
- function smd_um_active_users() {
- global $smd_um_event;
- $smd_um_prefs = smd_um_get_prefs();
- $curr_users = unserialize(get_pref('smd_um_current_users', '', 1));
- $timeout = get_pref('smd_um_active_timeout', $smd_um_prefs['smd_um_active_timeout']['default']);
- $online = array();
- if (is_array($curr_users)) {
- foreach ($curr_users as $user => $last_access) {
- $still_active = strtotime("+$timeout seconds", $last_access);
- if ( ($still_active !== false) && ($still_active > time()) ) {
- $online[] = eLink($smd_um_event, '', 'search_method', 'login_name', $user, 'crit', $user);
- }
- }
- }
- return ($online) ? '<div class="smd_um_active_users">' . gTxt('smd_um_active') . join(', ', $online) . '</div>' : '';
- }
- // ------------------------
- // Update any language string. Note this may leave orphan strings if the name is changed
- function smd_um_upsert_lang($title, $name='') {
- global $textarray;
- $lang = get_pref('language', 'en-gb');
- $name = (isset($name) && $name != '') ? $name : strtolower(sanitizeForUrl($title));
- $table = 'txp_lang';
- $where = "name='" . doSlash($name) . "' AND lang='" . doSlash($lang) . "'";
- // Try to update first
- $ret = safe_update($table, "data='" . doSlash($title) . "'", $where);
- if ($ret && (mysql_affected_rows() || safe_count($table, $where))) {
- // Do nothing -- record has been updated
- } else {
- safe_insert($table, "event='admin', name='" . doSlash($name) . "', lang='" . …
Large files files are truncated, but you can click here to view the full file