Source for file users.ctrl.php
Documentation is available at users.ctrl.php
* This file implements the UI controller for settings management.
* This file is part of Quam Plures - {@link http://quamplures.net/}
* See also {@link https://launchpad.net/quam-plures}.
* @copyright (c) 2009 - 2011 by the Quam Plures developers - {@link http://quamplures.net/}
* @copyright (c)2003-2009 by Francois PLANQUE - {@link http://fplanque.net/}
* Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
* {@internal License choice
* - If you have received this file as part of a package, please find the license.txt file in
* the same folder or the closest folder above for complete license terms.
* - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
* then you must choose one of the following licenses before using the file:
* - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
* - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
* {@internal Open Source relicensing agreement:
* Daniel HAHLER grants Francois PLANQUE the right to license
* Daniel HAHLER's contributions to this file and the b2evolution project
* under any OSI approved OSS license (http://www.opensource.org/licenses/).
* {@internal Below is a list of authors who have contributed to design/coding of this file: }}
* @author fplanque: Francois PLANQUE
* @author blueyed: Daniel HAHLER
* @todo separate object inits and permission checks
if( !defined('QP_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
$AdminUI->set_path( 'users' );
param( 'user_ID', 'integer', NULL ); // Note: should NOT be memorized (would kill navigation/sorting) use memorize_param() if needed
param( 'grp_ID', 'integer', NULL ); // Note: should NOT be memorized: -- " --
* @global boolean true, if user is only allowed to edit his profile
$user_profile_only = ! $current_User->check_perm( 'users', 'view' );
{ // User has no permissions to view: he can only edit his profile
if( (isset ($user_ID) && $user_ID != $current_User->ID)
{ // User is trying to edit something he should not: add error message (Should be prevented by UI)
$Messages->add( T_('You have no permission to view other users or groups!'), 'error' );
// Make sure the user only edits himself:
$user_ID = $current_User->ID;
if( ! in_array( $action, array( 'userupdate', 'edit_user', 'default_settings' ) ) )
* Load editable objects and set $action (while checking permissions)
if( $action == 'userupdate' && $user_ID == 0 )
{ // we create a new user
$edited_User = new User();
$edited_User->set_datecreated( $localtimenow );
elseif( ($edited_User = & $UserCache->get_by_ID( $user_ID, false )) === false )
{ // We could not find the User to edit:
$Messages->head = T_('Cannot edit user!');
$Messages->add( T_('Requested user does not exist any longer.'), 'error' );
elseif( $action == 'list' )
{ // 'list' is default, $user_ID given
if( $user_ID == $current_User->ID || $current_User->check_perm( 'users', 'edit' ) )
if( $action != 'view_user' && $action != 'list' )
{ // check edit permissions
if( ! $current_User->check_perm( 'users', 'edit' )
&& $edited_User->ID != $current_User->ID )
{ // user is only allowed to _view_ other user's profiles
$Messages->add( T_('You have no permission to edit other users!'), 'error' );
{ // Demo mode restrictions: admin/demouser/demoblogger/demospecial cannot be edited
if( $edited_User->ID == 1
|| $edited_User->login == 'demouser'
|| $edited_User->login == 'demoblogger'
|| $edited_User->login == 'demospecial' )
$Messages->add( T_('Demo mode: you cannot edit the admin\'s or any demo-name\'s profile!'), 'error' );
if( strpos( $action, 'delete_' ) === 0 || $action == 'promote' )
{ // Fallback to list/view action
elseif( $grp_ID !== NULL )
if( $action == 'groupupdate' && $grp_ID == 0 )
$edited_Group = new Group();
elseif( ($edited_Group = & $GroupCache->get_by_ID( $grp_ID, false )) === false )
{ // We could not find the Group to edit:
$Messages->head = T_('Cannot edit group!');
$Messages->add( T_('Requested group does not exist any longer.'), 'error' );
elseif( $action == 'list' )
{ // 'list' is default, $grp_ID given
if( $current_User->check_perm( 'users', 'edit' ) )
if( $action != 'view_group' && $action != 'list' )
{ // check edit permissions
if( !$current_User->check_perm( 'users', 'edit' ) )
$Messages->add( T_('You have no permission to edit groups!'), 'error' );
{ // Additional checks for demo mode: no changes to admin's and demo<name>'s group allowed
$admin_User = & $UserCache->get_by_ID(1);
$demo_User = & $UserCache->get_by_login('demouser');
$blogger_User = & $UserCache->get_by_login('demoblogger');
$special_User = & $UserCache->get_by_login('demospecial');
if( $edited_Group->ID == $admin_User->Group->ID
|| $edited_Group->ID == $demo_User->group_ID
|| $edited_Group->ID == $blogger_User->group_ID
|| $edited_Group->ID == $special_User->group_ID )
$Messages->add( T_('You cannot edit the groups of user «admin» or any «demo-name» in demo mode!'), 'error' );
* Perform actions, if there were no errors:
if( !$Messages->count('error') )
// We want to create a new user:
if( isset ( $edited_User ) )
{ // We want to use a template
$new_User = $edited_User; // Copy !
$new_User->set( 'ID', 0 );
$edited_User = & $new_User;
{ // We use an empty user:
$edited_User = new User();
// Determine if the user must validate before using the system:
$edited_User->set( 'validated', ! $Settings->get('newusers_mustvalidate') );
case 'change_admin_template':
// Template switch from menu
param( 'new_admin_template', 'string', true );
param( 'redirect_to', 'string', '' );
$UserSettings->set( 'admin_template', $new_admin_template );
$UserSettings->dbupdate();
$Messages->add( sprintf( T_('Admin template changed to «%s»'), $new_admin_template ), 'success' );
// Update existing user OR create new user:
if( empty($edited_User) || !is_object($edited_User) )
$Messages->add( 'No user set!' ); // Needs no translation, should be prevented by UI.
$reload_page = false; // We set it to true, if a setting changes that needs a page reload (locale, admin template, ..)
if( !$current_User->check_perm( 'users', 'edit' ) && $edited_User->ID != $current_User->ID )
{ // user is only allowed to update him/herself
$Messages->add( T_('You are only allowed to update your own profile!'), 'error' );
param( 'edited_user_login', 'string' );
// We want all logins to be lowercase to guarantee uniqueness regardless of the database case handling for UNIQUE indexes:
$edited_user_login = strtolower( $edited_user_login );
if( $current_User->check_perm( 'users', 'edit' ) )
{ // changing level/group is allowed (not in profile mode)
$edited_User->set( 'level', $edited_user_level );
param( 'edited_user_validated', 'integer', 0 );
if( $edited_User->set( 'validated', $edited_user_validated ) && $edited_User->ID == $current_User->ID )
{ // validated value has changed for the current user
param( 'edited_user_grp_ID', 'integer', true );
$edited_user_Group = $GroupCache->get_by_ID( $edited_user_grp_ID );
$edited_User->set_Group( $edited_user_Group );
// $edited_User->Group->disp('name');
// check if new login already exists for another user_ID
WHERE user_login = '. $DB->quote($edited_user_login). '
AND user_ID != '. $edited_User->ID;
if( $q = $DB->get_var( $query ) )
sprintf( T_('This login already exists. Do you want to <a %s>edit the existing user</a>?'),
'href="?ctrl=users&user_ID='. $q. '"' ) );
param( 'edited_user_firstname', 'string', true );
param( 'edited_user_lastname', 'string', true );
param( 'edited_user_nickname', 'string', true );
param( 'edited_user_idmode', 'string', true );
param( 'edited_user_locale', 'string', true );
param( 'edited_user_email', 'string', true );
param( 'edited_user_url', 'string', true );
param( 'edited_user_allow_msgform', 'integer', 0 );
param( 'edited_user_notify', 'integer', 0 );
param( 'edited_user_showonline', 'integer', 0 );
param( 'edited_user_set_login_multiple_sessions', 'integer', 0 );
param( 'edited_user_pass1', 'string', true );
param( 'edited_user_pass2', 'string', true );
if( ! param_check_passwords( 'edited_user_pass1', 'edited_user_pass2', ($edited_User->ID == 0) ) ) // required for new users
{ // passwords not the same or empty: empty them for the form
$edited_User->set( 'login', $edited_user_login );
$edited_User->set( 'firstname', $edited_user_firstname );
$edited_User->set( 'lastname', $edited_user_lastname );
$edited_User->set( 'nickname', $edited_user_nickname );
$edited_User->set( 'idmode', $edited_user_idmode );
if( $edited_User->set( 'locale', $edited_user_locale ) && $edited_User->ID == $current_User->ID )
{ // locale value has changed for the current user
$edited_User->set( 'email', $edited_user_email );
$edited_User->set( 'url', $edited_user_url );
$edited_User->set( 'allow_msgform', $edited_user_allow_msgform );
$edited_User->set( 'notify', $edited_user_notify );
$edited_User->set( 'showonline', $edited_user_showonline );
param( 'edited_user_admin_template', 'string', true );
param_integer_range( 'edited_user_action_icon_threshold', 1, 5, T_('The threshold must be between 1 and 5.') );
param_integer_range( 'edited_user_action_word_threshold', 1, 5, T_('The threshold must be between 1 and 5.') );
param( 'edited_user_legend', 'integer', 0 );
param( 'edited_user_bozo', 'integer', 0 );
param( 'edited_user_focusonfirst', 'integer', 0 );
param( 'edited_user_results_per_page', 'integer', null );
param( 'edited_user_num_admin_blogs', 'integer', null );
* @todo EdB: probably don't need the messages->count(error) bit
* but it doesn't hurt and can be removed later by someone smart.
* A bunch of "experimental user field" stuff used to be here ...
if( $Messages->count( 'error' ) )
{ // We have found validation errors:
if( !empty($edited_user_pass2) )
{ // Password provided, we must encode it
$new_pass = md5( $edited_user_pass2 );
$edited_User->set( 'pass', $new_pass ); // set password
if( $edited_User->ID != 0 )
{ // Commit update to the DB:
$update_r = $edited_User->dbupdate();
if( $edited_User->ID == $current_User->ID )
{ // User updates his profile:
$Messages->add( T_('Your profile has been updated.'), 'success' );
$Messages->add( T_('Your profile has not been changed.'), 'note' );
$Messages->add( T_('User updated.'), 'success' );
$edited_User->dbinsert();
$Messages->add( T_('New user created.'), 'success' );
// Now that the User exists in the DB and has an ID, update the settings:
$UserSettings->set( 'login_multiple_sessions', $edited_user_set_login_multiple_sessions, $edited_User->ID );
if( $UserSettings->set( 'admin_template', $edited_user_admin_template, $edited_User->ID )
&& ($edited_User->ID == $current_User->ID) )
{ // admin_template has changed or was set the first time for the current user
$UserSettings->set( 'action_icon_threshold', $edited_user_action_icon_threshold, $edited_User->ID );
$UserSettings->set( 'action_word_threshold', $edited_user_action_word_threshold, $edited_User->ID );
$UserSettings->set( 'display_icon_legend', $edited_user_legend, $edited_User->ID );
// Set bozo validador activation
$UserSettings->set( 'control_form_abortions', $edited_user_bozo, $edited_User->ID );
$UserSettings->set( 'focus_on_first_input', $edited_user_focusonfirst, $edited_User->ID );
if( isset ($edited_user_results_per_page) )
$UserSettings->set( 'results_per_page', $edited_user_results_per_page, $edited_User->ID );
// Number of blogs to display in admin
if( isset ($edited_user_num_admin_blogs) )
$UserSettings->set( 'num_admin_blogs', $edited_user_num_admin_blogs, $edited_User->ID );
if( $UserSettings->dbupdate() )
$Messages->add( T_('User feature settings have been changed.'), 'success');
$any_plugin_settings_updated = false;
while( $loop_Plugin = & $Plugins->get_next() )
$pluginusersettings = $loop_Plugin->GetDefaultUserSettings( $tmp_params = array('for_editing'=> true) );
if( empty($pluginusersettings) )
// Loop through settings for this plugin:
foreach( $pluginusersettings as $set_name => $set_meta )
// Let the plugin handle custom fields:
$ok_to_update = $Plugins->call_method( $loop_Plugin->ID, 'PluginUserSettingsUpdateAction', $tmp_params = array(
'User' => & $edited_User, 'action' => 'save' ) );
if( $ok_to_update === false )
$any_plugin_settings_updated = true;
if( $any_plugin_settings_updated )
$Messages->add( T_('Usersettings of Plugins have been updated.'), 'success' );
{ // reload the current page through header redirection:
if( $action != 'edit_user' )
$reload_page = false; // We set it to true, if a setting changes that needs a page reload (locale, admin template, ..)
$cur_admin_template = $UserSettings->get('admin_template');
$UserSettings->delete( 'admin_template', $edited_User->ID );
&& $UserSettings->get('admin_template', $edited_User->ID ) != $cur_admin_template
&& ($edited_User->ID == $current_User->ID) )
{ // admin_template has changed:
// Remove all UserSettings where a default exists:
foreach( $UserSettings->_defaults as $k => $v )
$UserSettings->delete( $k, $edited_User->ID );
if( $UserSettings->dbupdate() ) $Messages->add( T_('User feature settings have been changed.'), 'success');
$any_plugin_settings_updated = false;
while( $loop_Plugin = & $Plugins->get_next() )
$pluginusersettings = $loop_Plugin->GetDefaultUserSettings( $tmp_params = array('for_editing'=> true) );
if( empty($pluginusersettings) )
foreach( $pluginusersettings as $k => $l_meta )
if( isset ($l_meta['layout']) || ! empty($l_meta['no_edit']) )
{ // a layout "setting" or not for editing
// Let the plugin handle custom fields:
$ok_to_update = $Plugins->call_method( $loop_Plugin->ID, 'PluginUserSettingsUpdateAction', $tmp_params = array(
'User' => & $edited_User, 'action' => 'reset' ) );
if( $ok_to_update === false )
$any_plugin_settings_updated = true;
if( $any_plugin_settings_updated )
$Messages->add( T_('Usersettings of Plugins have been updated.'), 'success' );
// Always display the profile again:
{ // reload the current page through header redirection:
param( 'prom', 'string', true );
|| ! in_array( $prom, array('up', 'down') )
|| ( $prom == 'up' && $edited_User->get('level') > 9 )
|| ( $prom == 'down' && $edited_User->get('level') < 1 )
$Messages->add( T_('Invalid promotion.'), 'error' );
SET user_level = user_level '. ( $prom == 'up' ? '+' : '-' ). ' 1
WHERE user_ID = '. $edited_User->ID;
$Messages->add( T_('User level changed.'), 'success' );
$Messages->add( sprintf( 'Couldn\'t change %s\'s level.', $edited_User->login ), 'error' );
if( !isset ($edited_User) )
if( $edited_User->ID == $current_User->ID )
$Messages->add( T_('You can\'t delete yourself!'), 'error' );
if( $edited_User->ID == 1 )
$Messages->add( T_('You can\'t delete User #1!'), 'error' );
$fullname = $edited_User->dget( 'fullname' );
if( param( 'confirm', 'integer', 0 ) )
{ // confirmed, Delete from DB:
if ( ! empty( $fullname ) )
$msg = sprintf( T_('User «%s» [%s] deleted.'), $fullname, $edited_User->dget( 'login' ) );
$msg = sprintf( T_('User «%s» deleted.'), $edited_User->dget( 'login' ) );
$edited_User->dbdelete( $Messages );
$Messages->add( $msg, 'success' );
{ // not confirmed, Check for restrictions:
if ( ! empty( $fullname ) )
$msg = sprintf( T_('Cannot delete User «%s» [%s]'), $fullname, $edited_User->dget( 'login' ) );
$msg = sprintf( T_('Cannot delete User «%s»'), $edited_User->dget( 'login' ) );
if( ! $edited_User->check_delete( $msg ) )
{ // There are restrictions:
// Delete a set of an array type setting:
param( 'plugin_ID', 'integer', true );
$admin_Plugins = & get_Cache('Plugins_admin');
$admin_Plugins->restart();
$edit_Plugin = & $admin_Plugins->get_by_ID($plugin_ID);
$edit_Plugin->Settings->dbupdate();
case 'add_settings_set': // delegates to edit_settings
// Add a new set to an array type setting:
param( 'plugin_ID', 'integer', true );
param( 'set_path', 'string', '' );
$admin_Plugins = & get_Cache('Plugins_admin');
$admin_Plugins->restart();
$edit_Plugin = & $admin_Plugins->get_by_ID($plugin_ID);
$edit_Plugin->Settings->dbupdate();
// ---- GROUPS --------------------------------------------------------------------------------------
// We want to create a new group:
if( isset ( $edited_Group ) )
{ // We want to use a template
$new_Group = $edited_Group; // Copy !
$new_Group->set( 'ID', 0 );
$edited_Group = & $new_Group;
{ // We use an empty group:
$edited_Group = new Group();
if( empty($edited_Group) || !is_object($edited_Group) )
$Messages->add( 'No group set!' ); // Needs no translation, should be prevented by UI.
param( 'edited_grp_name', 'string' );
// check if the group name already exists for another group
$query = 'SELECT grp_ID FROM T_groups
WHERE grp_name = '. $DB->quote($edited_grp_name). '
AND grp_ID != '. $edited_Group->ID;
if( $q = $DB->get_var( $query ) )
sprintf( T_('This group name already exists! Do you want to <a %s>edit the existing group</a>?'),
'href="?ctrl=users&grp_ID='. $q. '"' ) );
$edited_Group->set( 'name', $edited_grp_name );
$edited_Group->set( 'perm_blogs', param( 'edited_grp_perm_blogs', 'string', true ) );
$edited_Group->set( 'perm_bypass_antispam', param( 'apply_antispam', 'integer', 0 ) ? 0 : 1 );
$edited_Group->set( 'perm_xhtmlvalidation', param( 'perm_xhtmlvalidation', 'string', true ) );
$edited_Group->set( 'perm_xhtmlvalidation_xmlrpc', param( 'perm_xhtmlvalidation_xmlrpc', 'string', true ) );
$edited_Group->set( 'perm_xhtml_css_tweaks', param( 'prevent_css_tweaks', 'integer', 0 ) ? 0 : 1 );
$edited_Group->set( 'perm_xhtml_iframes', param( 'prevent_iframes', 'integer', 0 ) ? 0 : 1 );
$edited_Group->set( 'perm_xhtml_javascript', param( 'prevent_javascript', 'integer', 0 ) ? 0 : 1 );
$edited_Group->set( 'perm_xhtml_objects', param( 'prevent_objects', 'integer', 0 ) ? 0 : 1 );
$edited_Group->set( 'perm_spamblacklist', param( 'edited_grp_perm_spamblacklist', 'string', true ) );
$edited_Group->set( 'perm_templates', param( 'edited_grp_perm_templates', 'integer', 0 ) );
$edited_Group->set( 'perm_stats', param( 'edited_grp_perm_stats', 'string', true ) );
$edited_Group->set( 'perm_options', param( 'edited_grp_perm_options', 'string', true ) );
$edited_Group->set( 'perm_files', param( 'edited_grp_perm_files', 'string', true ) );
if( $edited_Group->ID != 1 )
{ // Groups others than #1 can be prevented from logging in or editing users
$edited_Group->set( 'perm_admin', param( 'edited_grp_perm_admin', 'string', true ) );
$edited_Group->set( 'perm_users', param( 'edited_grp_perm_users', 'string', true ) );
if( $Messages->count( 'error' ) )
{ // We have found validation errors:
if( $edited_Group->ID == 0 )
$edited_Group->dbinsert();
$Messages->add( T_('New group created.'), 'success' );
{ // Commit update to the DB:
$edited_Group->dbupdate();
$Messages->add( T_('Group updated.'), 'success' );
// Commit changes in cache:
$GroupCache->add( $edited_Group );
if( !isset ($edited_Group) )
if( $edited_Group->ID == 1 )
$Messages->add( T_('You can\'t delete Group #1!'), 'error' );
if( $edited_Group->ID == $Settings->get('newusers_grp_ID' ) )
$Messages->add( T_('You can\'t delete the default group for new users!'), 'error' );
if( param( 'confirm', 'integer', 0 ) )
{ // confirmed, Delete from DB:
$msg = sprintf( T_('Group «%s» deleted.'), $edited_Group->dget( 'name' ) );
$edited_Group->dbdelete( $Messages );
$Messages->add( $msg, 'success' );
{ // not confirmed, Check for restrictions:
if( ! $edited_Group->check_delete( sprintf( T_('Cannot delete Group «%s»'), $edited_Group->dget( 'name' ) ) ) )
{ // There are restrictions:
// We might delegate to this action from above:
if( $action == 'edit_user' )
$Plugins->trigger_event( 'PluginUserSettingsEditAction', $tmp_params = array( 'User' => & $edited_User ) );
$Session->delete( 'core.changepwd.request_id' ); // delete the request_id for password change request (from /qp_srvc/login.php)
// Display <html><head>...</head> section! (Note: should be done early if actions do not redirect)
$AdminUI->disp_html_head();
// Display title, menu, messages, etc. (Note: messages MUST be displayed AFTER the actions)
$AdminUI->disp_body_top();
* Display appropriate payload:
// We need to ask for confirmation:
$fullname = $edited_User->dget( 'fullname' );
if ( ! empty( $fullname ) )
$msg = sprintf( T_('Delete user «%s» [%s]?'), $fullname, $edited_User->dget( 'login' ) );
$msg = sprintf( T_('Delete user «%s»?'), $edited_User->dget( 'login' ) );
$edited_User->confirm_delete( $msg, $action, get_memorized( 'action' ) );
$AdminUI->disp_view( 'users/views/_user.form.php' );
// We need to ask for confirmation:
$edited_Group->confirm_delete(
sprintf( T_('Delete group «%s»?'), $edited_Group->dget( 'name' ) ),
$AdminUI->disp_view( 'users/views/_group.form.php' );
// NOTE: we don't want this (potentially very long) list to be displayed again and again)
$AdminUI->disp_payload_begin();
$AdminUI->disp_view( 'users/views/_user_list.view.php' );
$AdminUI->disp_payload_end();
// Display body bottom, debug info and close </html>:
$AdminUI->disp_global_footer();
|