.
*/
/**
* Users panel.
*
* @package Admin\Admin
*/
use Textpattern\Search\Filter;
if (!defined('txpinterface')) {
die('txpinterface is undefined.');
}
$levels = get_groups();
if ($event == 'admin') {
require_privs('admin');
include_once txpath.'/lib/txplib_admin.php';
$available_steps = array(
'admin_multi_edit' => true,
'admin_change_pageby' => true,
'author_list' => false,
'author_edit' => false,
'author_save' => true,
'author_save_new' => true,
'change_email' => true,
'change_email_form' => false,
'change_pass' => true,
'new_pass_form' => false,
);
if ($step && bouncer($step, $available_steps)) {
$step();
} else {
author_list();
}
}
/**
* Changes an email address.
*/
function change_email()
{
global $txp_user;
$new_email = ps('new_email');
if (!is_valid_email($new_email)) {
change_email_form(array(gTxt('email_required'), E_ERROR));
return;
}
$rs = update_user($txp_user, $new_email);
if ($rs) {
author_list(gTxt('email_changed', array('{email}' => $new_email)));
return;
}
change_email_form(array(gTxt('author_save_failed'), E_ERROR));
}
/**
* Updates a user.
*/
function author_save()
{
global $txp_user;
require_privs('admin.edit');
extract(psa(array(
'privs',
'name',
'RealName',
'email',
)));
$privs = assert_int($privs);
if (!is_valid_email($email)) {
author_edit(array(gTxt('email_required'), E_ERROR));
return;
}
$rs = update_user($name, $email, $RealName);
if ($rs && ($txp_user === $name || change_user_group($name, $privs))) {
author_list(gTxt('author_updated', array('{name}' => $RealName)));
return;
}
author_edit(array(gTxt('author_save_failed'), E_ERROR));
}
/**
* Changes current user's password.
*/
function change_pass()
{
global $txp_user;
extract(psa(array('current_pass', 'new_pass')));
if (empty($new_pass)) {
new_pass_form(array(gTxt('password_required'), E_ERROR));
return;
}
if (txp_validate($txp_user, $current_pass)) {
$rs = change_user_password($txp_user, $new_pass);
if ($rs) {
$message = gTxt('password_changed');
author_list($message);
}
} else {
new_pass_form(array(gTxt('password_invalid'), E_ERROR));
}
}
/**
* Creates a new user.
*/
function author_save_new()
{
require_privs('admin.edit');
extract(psa(array(
'privs',
'name',
'email',
'RealName',
)));
$privs = assert_int($privs);
if (is_valid_username($name) && is_valid_email($email)) {
if (user_exists($name)) {
author_edit(array(gTxt('author_already_exists', array('{name}' => $name)), E_ERROR));
return;
}
$password = Txp::get('\Textpattern\Password\Random')->generate(PASSWORD_LENGTH);
$rs = create_user($name, $email, $password, $RealName, $privs);
if ($rs) {
$message = send_account_activation($name);
author_list($message);
return;
}
}
author_edit(array(gTxt('error_adding_new_author'), E_ERROR));
}
/**
* Lists user groups as a <select> input.
*
* @param int $priv Selected option
* @return string HTML
*/
function privs($priv = '')
{
global $levels;
return selectInput('privs', $levels, $priv, '', '', 'privileges');
}
/**
* Translates a numeric ID to a human-readable user group.
*
* @param int $priv The group
* @return string
*/
function get_priv_level($priv)
{
global $levels;
return $levels[$priv];
}
/**
* Password changing form.
*
* @param string|array $message The activity message
*/
function new_pass_form($message = '')
{
pagetop(gTxt('tab_site_admin'), $message);
echo form(
hed(gTxt('change_password'), 2).
inputLabel(
'current_pass',
fInput('password', 'current_pass', '', '', '', '', INPUT_REGULAR, '', 'current_pass'),
'current_password', '', array('class' => 'txp-form-field edit-admin-current-password')
).
inputLabel(
'new_pass',
fInput('password', 'new_pass', '', 'txp-maskable txp-strength-hint', '', '', INPUT_REGULAR, '', 'new_pass').
n.tag(null, 'div', array('class' => 'strength-meter')).
n.tag(
checkbox('unmask', 1, false, 0, 'show_password').
n.tag(gTxt('show_password'), 'label', array('for' => 'show_password')),
'div', array('class' => 'edit-admin-show-password')),
'new_password', '', array('class' => 'txp-form-field edit-admin-new-password')
).
graf(
sLink('admin', '', gTxt('cancel'), 'txp-button').
fInput('submit', 'change_pass', gTxt('submit'), 'publish'),
array('class' => 'txp-edit-actions')
).
eInput('admin').
sInput('change_pass'),
'', '', 'post', 'txp-edit', '', 'change_password');
}
/**
* Email changing form.
*
* @param string|array $message The activity message
*/
function change_email_form($message = '')
{
global $txp_user;
pagetop(gTxt('tab_site_admin'), $message);
$email = fetch('email', 'txp_users', 'name', $txp_user);
echo form(
hed(gTxt('change_email_address'), 2).
inputLabel(
'new_email',
fInput('text', 'new_email', $email, '', '', '', INPUT_REGULAR, '', 'new_email'),
'new_email', '', array('class' => 'txp-form-field edit-admin-new-email')
).
graf(
sLink('admin', '', gTxt('cancel'), 'txp-button').
fInput('submit', 'change_email', gTxt('submit'), 'publish'),
array('class' => 'txp-edit-actions')
).
eInput('admin').
sInput('change_email'),
'', '', 'post', 'txp-edit', '', 'change_email');
}
/**
* The main panel listing all authors.
*
* @param string|array $message The activity message
*/
function author_list($message = '')
{
global $event, $txp_user, $author_list_pageby, $levels;
pagetop(gTxt('tab_site_admin'), $message);
if (is_disabled('mail')) {
echo graf(
span(null, array('class' => 'ui-icon ui-icon-alert')).' '.
gTxt('warn_mail_unavailable'),
array('class' => 'alert-block warning')
);
}
$buttons = array();
// Change password button.
$buttons[] = sLink('admin', 'new_pass_form', gTxt('change_password'), 'txp-button');
if (!has_privs('admin.edit')) {
// Change email address button.
$buttons[] = sLink('admin', 'change_email_form', gTxt('change_email_address'), 'txp-button');
} else {
// New author button.
$buttons[] = sLink('admin', 'author_edit', gTxt('add_new_author'), 'txp-button');
}
// User list.
if (has_privs('admin.list')) {
extract(gpsa(array(
'page',
'sort',
'dir',
'crit',
'search_method',
)));
if ($sort === '') {
$sort = get_pref('admin_sort_column', 'name');
} else {
if (!in_array($sort, array('name', 'RealName', 'email', 'privs', 'last_login'))) {
$sort = 'name';
}
set_pref('admin_sort_column', $sort, 'admin', 2, '', 0, PREF_PRIVATE);
}
if ($dir === '') {
$dir = get_pref('admin_sort_dir', 'asc');
} else {
$dir = ($dir == 'desc') ? "desc" : "asc";
set_pref('admin_sort_dir', $dir, 'admin', 2, '', 0, PREF_PRIVATE);
}
$sort_sql = $sort.' '.$dir;
$switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
$search = new Filter($event,
array(
'login' => array(
'column' => 'txp_users.name',
'label' => gTxt('login_name'),
),
'RealName' => array(
'column' => 'txp_users.RealName',
'label' => gTxt('real_name'),
),
'email' => array(
'column' => 'txp_users.email',
'label' => gTxt('email'),
),
'privs' => array(
'column' => array('txp_users.privs'),
'label' => gTxt('privileges'),
'type' => 'boolean',
),
)
);
$search->setAliases('privs', $levels);
list($criteria, $crit, $search_method) = $search->getFilter();
$search_render_options = array(
'placeholder' => 'search_users',
);
$total = getCount('txp_users', $criteria);
echo n.'
'.
n.tag(
hed(gTxt('tab_site_admin'), 1, array('class' => 'txp-heading')),
'div', array('class' => 'txp-layout-4col-alt')
);
$searchBlock =
n.tag(
$search->renderForm('author_list', $search_render_options),
'div', array(
'class' => 'txp-layout-4col-3span',
'id' => 'users_control',
)
);
$createBlock = array();
$createBlock[] = n.tag(implode(n, $buttons), 'div', array('class' => 'txp-control-panel'));
$contentBlockStart = n.tag_start('div', array(
'class' => 'txp-layout-1col',
'id' => 'users_container',
));
$createBlock = implode(n, $createBlock);
if ($total < 1) {
if ($criteria != 1) {
echo $searchBlock.
$contentBlockStart.
$createBlock.
graf(
span(null, array('class' => 'ui-icon ui-icon-info')).' '.
gTxt('no_results_found'),
array('class' => 'alert-block information')
).
n.tag_end('div'). // End of .txp-layout-1col.
n.'
'; // End of .txp-layout.
}
return;
}
$limit = max($author_list_pageby, 15);
list($page, $offset, $numPages) = pager($total, $limit, $page);
$use_multi_edit = (has_privs('admin.edit') && ($total > 1 or safe_count('txp_users', "1 = 1") > 1));
echo $searchBlock.$contentBlockStart.$createBlock;
$rs = safe_rows_start(
"*, UNIX_TIMESTAMP(last_access) AS last_login",
'txp_users',
"$criteria ORDER BY $sort_sql LIMIT $offset, $limit"
);
if ($rs) {
echo
n.tag_start('form', array(
'class' => 'multi_edit_form',
'id' => 'users_form',
'name' => 'longform',
'method' => 'post',
'action' => 'index.php',
)).
n.tag_start('div', array('class' => 'txp-listtables')).
n.tag_start('table', array('class' => 'txp-list')).
n.tag_start('thead').
tr(
(
($use_multi_edit)
? hCell(
fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'),
'', ' class="txp-list-col-multi-edit" scope="col" title="'.gTxt('toggle_all_selected').'"'
)
: hCell('', '', ' class="txp-list-col-multi-edit" scope="col"')
).
column_head(
'login_name', 'name', 'admin', true, $switch_dir, '', '',
(('name' == $sort) ? "$dir " : '').'txp-list-col-login-name name'
).
column_head(
'real_name', 'RealName', 'admin', true, $switch_dir, '', '',
(('RealName' == $sort) ? "$dir " : '').'txp-list-col-real-name name'
).
column_head(
'email', 'email', 'admin', true, $switch_dir, '', '',
(('email' == $sort) ? "$dir " : '').'txp-list-col-email'
).
column_head(
'privileges', 'privs', 'admin', true, $switch_dir, '', '',
(('privs' == $sort) ? "$dir " : '').'txp-list-col-privs'
).
column_head(
'last_login', 'last_login', 'admin', true, $switch_dir, '', '',
(('last_login' == $sort) ? "$dir " : '').'txp-list-col-last-login date'
)
).
n.tag_end('thead').
n.tag_start('tbody');
while ($a = nextRow($rs)) {
extract(doSpecial($a));
echo tr(
td(
((has_privs('admin.edit') and $txp_user != $a['name']) ? fInput('checkbox', 'selected[]', $a['name'], 'checkbox') : ''), '', 'txp-list-col-multi-edit'
).
hCell(
((has_privs('admin.edit')) ? eLink('admin', 'author_edit', 'user_id', $user_id, $name) : $name), '', ' class="txp-list-col-login-name name" scope="row"'
).
td(
$RealName, '', 'txp-list-col-real-name name'
).
td(
href($email, 'mailto:'.$email), '', 'txp-list-col-email'
).
td(
get_priv_level($privs), '', 'txp-list-col-privs'
).
td(
($last_login ? safe_strftime('%b %Y', $last_login) : ''), '', 'txp-list-col-last-login date'
)
);
}
echo
n.tag_end('tbody').
n.tag_end('table').
n.tag_end('div'). // End of .txp-listtables.
(
($use_multi_edit)
? author_multiedit_form($page, $sort, $dir, $crit, $search_method)
: ''
).
tInput().
n.tag_end('form').
n.tag_start('div', array(
'class' => 'txp-navigation',
'id' => 'users_navigation',
)).
pageby_form('admin', $author_list_pageby).
nav_form('admin', $page, $numPages, $sort, $dir, $crit, $search_method).
n.tag_end('div');
}
echo n.tag_end('div'); // End of .txp-layout-1col.
} else {
echo
n.tag_start('div', array(
'class' => 'txp-layout-1col',
'id' => 'users_container',
)).
n.tag(implode(n, $buttons), 'div', array('class' => 'txp-control-panel')).
n.tag_end('div'); // End of .txp-layout-1col.
}
echo n.''; // End of .txp-layout.
}
/**
* Renders and outputs the user editor panel.
*
* Accessing requires 'admin.edit' privileges.
*
* @param string|array $message The activity message
*/
function author_edit($message = '')
{
global $step, $txp_user;
require_privs('admin.edit');
pagetop(gTxt('tab_site_admin'), $message);
$vars = array('user_id', 'name', 'RealName', 'email', 'privs');
$rs = array();
$out = array();
extract(gpsa($vars));
$is_edit = ($user_id && $step == 'author_edit');
if ($is_edit) {
$user_id = assert_int($user_id);
$rs = safe_row("*", 'txp_users', "user_id = $user_id");
extract($rs);
}
if ($is_edit) {
$out[] = hed(gTxt('edit_author'), 2);
} else {
$out[] = hed(gTxt('add_new_author'), 2);
}
if ($is_edit) {
$out[] = inputLabel(
'login_name',
strong(txpspecialchars($name)),
'', '', array('class' => 'txp-form-field edit-admin-login-name')
);
} else {
$out[] = inputLabel(
'login_name',
fInput('text', 'name', $name, '', '', '', INPUT_REGULAR, '', 'login_name'),
'login_name', 'add_new_author', array('class' => 'txp-form-field edit-admin-login-name')
);
}
$out[] = inputLabel(
'real_name',
fInput('text', 'RealName', $RealName, '', '', '', INPUT_REGULAR, '', 'real_name'),
'real_name', '', array('class' => 'txp-form-field edit-admin-name')
).
inputLabel(
'login_email',
fInput('email', 'email', $email, '', '', '', INPUT_REGULAR, '', 'login_email'),
'email', '', array('class' => 'txp-form-field edit-admin-email')
);
if ($txp_user != $name) {
$out[] = inputLabel(
'privileges',
privs($privs),
'privileges', 'about_privileges', array('class' => 'txp-form-field edit-admin-privileges')
);
} else {
$out[] = inputLabel(
'privileges',
strong(get_priv_level($privs)),
'', '', array('class' => 'txp-form-field edit-admin-privileges')
).
hInput('privs', $privs);
}
$out[] = pluggable_ui('author_ui', 'extend_detail_form', '', $rs).
graf(
sLink('admin', '', gTxt('cancel'), 'txp-button').
fInput('submit', '', gTxt('save'), 'publish'),
array('class' => 'txp-edit-actions')
).
eInput('admin');
if ($user_id) {
$out[] = hInput('user_id', $user_id).
hInput('name', $name).
sInput('author_save');
} else {
$out[] = sInput('author_save_new');
}
echo form(join('', $out), '', '', 'post', 'txp-edit', '', 'user_edit');
}
/**
* Updates pageby value.
*/
function admin_change_pageby()
{
event_change_pageby('author');
author_list();
}
/**
* Renders multi-edit form.
*
* @param int $page The page
* @param string $sort The sorting value
* @param string $dir The sorting direction
* @param string $crit The search string
* @param string $search_method The search method
* @return string HTML
*/
function author_multiedit_form($page, $sort, $dir, $crit, $search_method)
{
$privileges = privs();
$users = safe_column("name", 'txp_users', "1 = 1");
$methods = array(
'changeprivilege' => array('label' => gTxt('changeprivilege'), 'html' => $privileges),
'resetpassword' => gTxt('resetpassword'),
'resendactivation' => gTxt('resend_activation'),
);
if (count($users) > 1) {
$methods['delete'] = array(
'label' => gTxt('delete'),
'html' => tag(gTxt('assign_assets_to'), 'label', array('for' => 'assign_assets')).
selectInput('assign_assets', $users, '', true, '', 'assign_assets'),
);
}
return multi_edit($methods, 'admin', 'admin_multi_edit', $page, $sort, $dir, $crit, $search_method);
}
/**
* Processes multi-edit actions.
*
* Accessing requires 'admin.edit' privileges.
*/
function admin_multi_edit()
{
global $txp_user;
require_privs('admin.edit');
$selected = ps('selected');
$method = ps('edit_method');
$changed = array();
$msg = '';
if (!$selected or !is_array($selected)) {
return author_list();
}
$clause = '';
if ($method === 'resetpassword') {
$clause = " AND last_access IS NOT NULL";
} elseif ($method === 'resendactivation') {
$clause = " AND last_access IS NULL";
}
$names = safe_column(
"name",
'txp_users',
"name IN (".join(',', quote_list($selected)).") AND name != '".doSlash($txp_user)."'".$clause
);
if (!$names) {
return author_list();
}
switch ($method) {
case 'delete':
$assign_assets = ps('assign_assets');
if (!$assign_assets) {
$msg = array('must_reassign_assets', E_ERROR);
} elseif (in_array($assign_assets, $names)) {
$msg = array('cannot_assign_assets_to_deletee', E_ERROR);
} elseif (remove_user($names, $assign_assets)) {
$changed = $names;
callback_event('authors_deleted', '', 0, $changed);
$msg = 'author_deleted';
}
break;
case 'changeprivilege':
if (change_user_group($names, ps('privs'))) {
$changed = $names;
$msg = 'author_updated';
}
break;
case 'resetpassword':
foreach ($names as $name) {
send_reset_confirmation_request($name);
$changed[] = $name;
}
$msg = 'password_reset_confirmation_request_sent';
break;
case 'resendactivation':
foreach ($names as $name) {
send_account_activation($name);
$changed[] = $name;
}
$msg = 'resend_activation_request_sent';
break;
}
if ($changed) {
return author_list(gTxt($msg, array('{name}' => txpspecialchars(join(', ', $changed)))));
}
author_list($msg);
}
/**
* Legacy panel.
*
* @param string|array $message
* @deprecated in 4.2.0
*/
function admin($message = '')
{
author_list($message);
}