requireAdminLogin()
->setPageTitle(WT_I18N::translate('User administration'));
require_once WT_ROOT.'includes/functions/functions_edit.php';
// Valid values for form variables
$ALL_ACTIONS=array('cleanup', 'cleanup2', 'createform', 'createuser', 'deleteuser', 'edituser', 'edituser2', 'listusers', 'loadrows', 'load1row');
$ALL_THEMES_DIRS=array();
foreach (get_theme_names() as $themename=>$themedir) {
$ALL_THEME_DIRS[]=$themedir;
}
$ALL_EDIT_OPTIONS=array(
'none' => /* I18N: Listbox entry; name of a role */ WT_I18N::translate('Visitor'),
'access'=> /* I18N: Listbox entry; name of a role */ WT_I18N::translate('Member'),
'edit' => /* I18N: Listbox entry; name of a role */ WT_I18N::translate('Editor'),
'accept'=> /* I18N: Listbox entry; name of a role */ WT_I18N::translate('Moderator'),
'admin' => /* I18N: Listbox entry; name of a role */ WT_I18N::translate('Manager')
);
// Form actions
$action =safe_GET('action', $ALL_ACTIONS, 'listusers');
$usrlang =safe_POST('usrlang', array_keys(WT_I18N::installed_languages()));
$username =safe_POST('username', WT_REGEX_USERNAME);
$filter =safe_POST('filter', WT_REGEX_NOSCRIPT);
$ged =safe_POST('ged', WT_REGEX_NOSCRIPT);
// Extract form variables
$oldusername =safe_POST('oldusername', WT_REGEX_USERNAME);
$oldemailaddress =safe_POST('oldemailaddress', WT_REGEX_EMAIL);
$realname =safe_POST('realname' );
$pass1 =safe_POST('pass1', WT_REGEX_PASSWORD);
$pass2 =safe_POST('pass2', WT_REGEX_PASSWORD);
$emailaddress =safe_POST('emailaddress', WT_REGEX_EMAIL);
$user_theme =safe_POST('user_theme', $ALL_THEME_DIRS);
$user_language =safe_POST('user_language', array_keys(WT_I18N::installed_languages()), WT_LOCALE);
$new_contact_method =safe_POST('new_contact_method');
$new_comment =safe_POST('new_comment', WT_REGEX_UNSAFE);
$new_auto_accept =safe_POST_bool('new_auto_accept');
$canadmin =safe_POST_bool('canadmin');
$visibleonline =safe_POST_bool('visibleonline');
$editaccount =safe_POST_bool('editaccount');
$verified =safe_POST_bool('verified');
$verified_by_admin =safe_POST_bool('verified_by_admin');
if (empty($ged)) {
$ged=$GEDCOM;
}
// Load all available gedcoms
$all_gedcoms = get_all_gedcoms();
//-- sorting by gedcom filename
asort($all_gedcoms);
switch ($action) {
case 'deleteuser':
// Delete a user - but don't delete ourselves!
$username=safe_GET('username');
$user_id=get_user_id($username);
if ($user_id && $user_id!=WT_USER_ID) {
delete_user($user_id);
AddToLog("deleted user ->{$username}<-", 'auth');
}
$action='listusers';
break;
case 'loadrows':
// Generate an AJAX/JSON response for datatables to load a block of rows
$sSearch=safe_GET('sSearch');
if ($sSearch) {
$WHERE=
" WHERE".
" user_name LIKE CONCAT('%', ?, '%') OR " .
" real_name LIKE CONCAT('%', ?, '%') OR " .
" email LIKE CONCAT('%', ?, '%')";
$ARGS=array($sSearch, $sSearch, $sSearch);
} else {
$WHERE="";
$ARGS=array();
}
$iDisplayStart =(int)safe_GET('iDisplayStart');
$iDisplayLength=(int)safe_GET('iDisplayLength');
set_user_setting(WT_USER_ID, 'admin_users_page_size', $iDisplayLength);
if ($iDisplayLength>0) {
$LIMIT=" LIMIT " . $iDisplayStart . ',' . $iDisplayLength;
} else {
$LIMIT="";
}
$iSortingCols=(int)safe_GET('iSortingCols');
if ($iSortingCols) {
$ORDER_BY=' ORDER BY ';
for ($i=0; $i<$iSortingCols; ++$i) {
// Datatables numbers columns 0, 1, 2, ...
// MySQL numbers columns 1, 2, 3, ...
switch (safe_GET('sSortDir_'.$i)) {
case 'asc':
$ORDER_BY.=(1+(int)safe_GET('iSortCol_'.$i)).' ASC ';
break;
case 'desc':
$ORDER_BY.=(1+(int)safe_GET('iSortCol_'.$i)).' DESC ';
break;
}
if ($i<$iSortingCols-1) {
$ORDER_BY.=',';
}
}
} else {
$ORDER_BY='';
}
$sql=
"SELECT SQL_CACHE SQL_CALC_FOUND_ROWS '', u.user_id, user_name, real_name, email, '', us1.setting_value, us2.setting_value, us2.setting_value, us3.setting_value, us3.setting_value, us4.setting_value, us5.setting_value".
" FROM `##user` u".
" LEFT JOIN `##user_setting` us1 ON (u.user_id=us1.user_id AND us1.setting_name='language')".
" LEFT JOIN `##user_setting` us2 ON (u.user_id=us2.user_id AND us2.setting_name='reg_timestamp')".
" LEFT JOIN `##user_setting` us3 ON (u.user_id=us3.user_id AND us3.setting_name='sessiontime')".
" LEFT JOIN `##user_setting` us4 ON (u.user_id=us4.user_id AND us4.setting_name='verified')".
" LEFT JOIN `##user_setting` us5 ON (u.user_id=us5.user_id AND us5.setting_name='verified_by_admin')".
$WHERE.
$ORDER_BY.
$LIMIT;
// This becomes a JSON list, not array, so need to fetch with numeric keys.
$aaData=WT_DB::prepare($sql)->execute($ARGS)->fetchAll(PDO::FETCH_NUM);
// Reformat various columns for display
foreach ($aaData as &$aData) {
// $aData[0] is a dummy column for the expand-details icon
// $aData[1] is the user ID
$user_id =$aData[1];
$user_name=$aData[2];
$aData[2]=edit_field_inline('user-user_name-'.$user_id, $aData[2]);
$aData[3]=edit_field_inline('user-real_name-'.$user_id, $aData[3]);
$aData[4]=edit_field_inline('user-email-'. $user_id, $aData[4]);
// $aData[5] is a link to an email icon
if ($user_id != WT_USER_ID) {
$aData[5]='
';
}
$aData[6]=edit_field_language_inline('user_setting-'.$user_id.'-language', $aData[6]);
// $aData[7] is the sortable registration timestamp
$aData[8]=format_timestamp($aData[8]);
if (date("U") - $aData[7] > 604800 && !$aData[11]) {
$aData[8]=''.$aData[8].'';
}
// $aData[9] is the sortable last-login timestamp
if ($aData[9]) {
$aData[10]=format_timestamp($aData[9]).' '.WT_I18N::time_ago(time() - $aData[9]);
} else {
$aData[10]=WT_I18N::translate('Never');
}
$aData[11]=edit_field_yes_no_inline('user_setting-'.$user_id.'-verified-', $aData[11]);
$aData[12]=edit_field_yes_no_inline('user_setting-'.$user_id.'-verified_by_admin-', $aData[12]);
// Add extra column for "delete" action
if ($user_id != WT_USER_ID) {
$aData[13]='';
} else {
// Do not delete ourself!
$aData[13]='';
}
}
// Total filtered/unfiltered rows
$iTotalDisplayRecords=WT_DB::prepare("SELECT FOUND_ROWS()")->fetchOne();
$iTotalRecords=WT_DB::prepare("SELECT COUNT(*) FROM `##user`")->fetchOne();
header('Content-type: application/json');
echo json_encode(array( // See http://www.datatables.net/usage/server-side
'sEcho' =>(int)safe_GET('sEcho'),
'iTotalRecords' =>$iTotalRecords,
'iTotalDisplayRecords'=>$iTotalDisplayRecords,
'aaData' =>$aaData
));
exit;
case 'load1row':
// Generate an AJAX response for datatables to load expanded row
$user_id=(int)safe_GET('user_id');
header('Content-type: text/html; charset=UTF-8');
echo '
', WT_I18N::translate('Restrict to immediate family'), help_link('RELATIONSHIP_PATH_LENGTH'), '
',
'
';
foreach ($all_gedcoms as $ged_id=>$ged_name) {
echo
'
',
WT_I18N::translate('%s', get_gedcom_setting($ged_id, 'title')),
//Pedigree root person
'
',
// TODO: autocomplete/find/etc. for this field
edit_field_inline('user_gedcom_setting-'.$user_id.'-'.$ged_id.'-rootid', get_user_gedcom_setting($user_id, $ged_id, 'rootid')),
'
',
// TODO: autocomplete/find/etc. for this field
edit_field_inline('user_gedcom_setting-'.$user_id.'-'.$ged_id.'-gedcomid', get_user_gedcom_setting($user_id, $ged_id, 'gedcomid')),
'
';
exit;
}
$controller->pageHeader();
// Save new user info to the database
if ($action=='createuser' || $action=='edituser2') {
if (($action=='createuser' || $action=='edituser2' && $username!=$oldusername) && get_user_id($username)) {
echo "", WT_I18N::translate('Duplicate user name. A user with that user name already exists. Please choose another user name.'), " ";
} elseif (($action=='createuser' || $action=='edituser2' && $emailaddress!=$oldemailaddress) && get_user_by_email($emailaddress)) {
echo "", WT_I18N::translate('Duplicate email address. A user with that email already exists.'), " ";
} else {
if ($pass1!=$pass2) {
echo "", WT_I18N::translate('Passwords do not match.'), " ";
} else {
// New user
if ($action=='createuser') {
if ($user_id=create_user($username, $realname, $emailaddress, $pass1)) {
set_user_setting($user_id, 'reg_timestamp', date('U'));
set_user_setting($user_id, 'sessiontime', '0');
AddToLog("User ->{$username}<- created", 'auth');
} else {
AddToLog("User ->{$username}<- was not created", 'auth');
$user_id=get_user_id($username);
}
} else {
$user_id=get_user_id($oldusername);
}
// Change password
if ($action=='edituser2' && !empty($pass1)) {
set_user_password($user_id, $pass1);
}
// Change username
if ($action=='edituser2' && $username!=$oldusername) {
rename_user($oldusername, $username);
AddToLog("User ->{$oldusername}<- renamed to ->{$username}<-", 'auth');
}
// Create/change settings that can be updated in the user's gedcom record?
$email_changed=($emailaddress!=getUserEmail($user_id));
$newly_verified=($verified_by_admin && !get_user_setting($user_id, 'verified_by_admin'));
// Create/change other settings
setUserFullName ($user_id, $realname);
setUserEmail ($user_id, $emailaddress);
set_user_setting($user_id, 'theme', $user_theme);
set_user_setting($user_id, 'language', $user_language);
set_user_setting($user_id, 'contactmethod', $new_contact_method);
set_user_setting($user_id, 'comment', $new_comment);
set_user_setting($user_id, 'auto_accept', $new_auto_accept);
set_user_setting($user_id, 'canadmin', $canadmin);
set_user_setting($user_id, 'visibleonline', $visibleonline);
set_user_setting($user_id, 'editaccount', $editaccount);
set_user_setting($user_id, 'verified', $verified);
set_user_setting($user_id, 'verified_by_admin', $verified_by_admin);
foreach ($all_gedcoms as $ged_id=>$ged_name) {
set_user_gedcom_setting($user_id, $ged_id, 'gedcomid', safe_POST_xref('gedcomid'.$ged_id));
set_user_gedcom_setting($user_id, $ged_id, 'rootid', safe_POST_xref('rootid'.$ged_id));
set_user_gedcom_setting($user_id, $ged_id, 'canedit', safe_POST('canedit'.$ged_id, array_keys($ALL_EDIT_OPTIONS)));
if (safe_POST_xref('gedcomid'.$ged_id)) {
set_user_gedcom_setting($user_id, $ged_id, 'RELATIONSHIP_PATH_LENGTH', safe_POST_integer('RELATIONSHIP_PATH_LENGTH'.$ged_id, 0, 10, 0));
} else {
// Do not allow a path length to be set if the individual ID is not
set_user_gedcom_setting($user_id, $ged_id, 'RELATIONSHIP_PATH_LENGTH', null);
}
}
// If we're verifying a new user, send them a message to let them know
if ($newly_verified && $action=='edituser2') {
WT_I18N::init($user_language);
$message=array();
$message["to"]=$username;
$headers="From: ".$WEBTREES_EMAIL;
$message["from"]=WT_USER_NAME;
$message["subject"]=WT_I18N::translate('Approval of account at %s', WT_SERVER_NAME.WT_SCRIPT_PATH);
$message["body"]=WT_I18N::translate('The administrator at the webtrees site %s has approved your application for an account. You may now login by accessing the following link: %s', WT_SERVER_NAME.WT_SCRIPT_PATH, WT_SERVER_NAME.WT_SCRIPT_PATH);
$message["created"]="";
$message["method"]="messaging2";
addMessage($message);
// and send a copy to the admin
/*
$message=array();
$message["to"]=WT_USER_NAME;
$headers="From: ".$WEBTREES_EMAIL;
$message["from"]=$username; // fake the from address - so the admin can "reply" to it.
$message["subject"]=WT_I18N::translate('Approval of account at %s', WT_SERVER_NAME.WT_SCRIPT_PATH));
$message["body"]=WT_I18N::translate('The administrator at the webtrees site %s has approved your application for an account. You may now login by accessing the following link: %s', WT_SERVER_NAME.WT_SCRIPT_PATH, WT_SERVER_NAME.WT_SCRIPT_PATH));
$message["created"]="";
$message["method"]="messaging2";
addMessage($message); */
}
}
}
} else {
if (get_gedcom_count()==1) { //Removed becasue it doesn't work here for multiple GEDCOMs. Can be reinstated when fixed (https://bugs.launchpad.net/webtrees/+bug/613235)
if ($ENABLE_AUTOCOMPLETE) require WT_ROOT.'js/autocomplete.js.htm';
}
}
// -- echo out the form to add a new user
// NOTE: WORKING
switch ($action) {
case 'createform':
init_calendar_popup();
$controller->addInlineJavaScript('
function checkform(frm) {
if (frm.username.value=="") {
alert("'.addslashes(WT_I18N::translate('You must enter a user name.')).'");
frm.username.focus();
return false;
}
if (frm.realname.value=="") {
alert("'.addslashes(WT_I18N::translate('You must enter a real name.')).'");
frm.realname.focus();
return false;
}
if (frm.pass1.value=="") {
alert("'.addslashes(WT_I18N::translate('You must enter a password.')).'");
frm.pass1.focus();
return false;
}
if (frm.pass2.value=="") {
alert("'.addslashes(WT_I18N::translate('You must confirm the password.')).'");
frm.pass2.focus();
return false;
}
if (frm.pass1.value.length < 6) {
alert("'.addslashes(WT_I18N::translate('Passwords must contain at least 6 characters.')).'");
frm.pass1.value = "";
frm.pass2.value = "";
frm.pass1.focus();
return false;
}
if (frm.emailaddress.value.indexOf("@")==-1) {
alert("'.addslashes(WT_I18N::translate('You must enter an email address.')).'");
frm.emailaddress.focus();
return false;
}
return true;
}
var pastefield;
function paste_id(value) {
pastefield.value=value;
}
jQuery(".relpath").change(function() {
var fieldIDx = jQuery(this).attr("id");
var idNum = fieldIDx.replace("RELATIONSHIP_PATH_LENGTH","");
var newIDx = "gedcomid"+idNum;
if (jQuery("#"+newIDx).val()=="") {
alert("'.addslashes(WT_I18N::translate('You must specify an individual record before you can restrict the user to their immediate family.')).'");
jQuery(this).val("");
}
});
');
?>
$user_name) {
$var = "del_".str_replace(array(".", "-", " "), array("_", "_", "_"), $user_name);
if (safe_POST($var)=='1') {
delete_user($user_id);
AddToLog("deleted user ->{$user_name}<-", 'auth');
echo WT_I18N::translate('Deleted user: '); echo $user_name, " ";
} else {
$tempArray = unserialize(get_user_setting($user_id, 'canedit'));
if (is_array($tempArray)) {
foreach ($tempArray as $gedid=>$data) {
$var = "delg_".str_replace(array(".", "-", " "), "_", $gedid);
if (safe_POST($var)=='1' && get_user_gedcom_setting($user_id, $gedid, 'canedit')) {
set_user_gedcom_setting($user_id, $gedid, 'canedit', null);
echo $gedid, ": ", WT_I18N::translate('Unset GEDCOM rights for '), $user_name, " ";
}
}
}
$tempArray = unserialize(get_user_setting($user_id, 'rootid'));
if (is_array($tempArray)) {
foreach ($tempArray as $gedid=>$data) {
$var = "delg_".str_replace(array(".", "-", " "), "_", $gedid);
if (safe_POST($var)=='1' && get_user_gedcom_setting($user_id, $gedid, 'rootid')) {
set_user_gedcom_setting($user_id, $gedid, 'rootid', null);
echo $gedid, ": ", WT_I18N::translate('Unset root ID for '), $user_name, " ";
}
}
}
$tempArray = unserialize(get_user_setting($user_id, 'gedcomid'));
if (is_array($tempArray)) {
foreach ($tempArray as $gedid=>$data) {
$var = "delg_".str_replace(array(".", "-", " "), "_", $gedid);
if (safe_POST($var)=='1' && get_user_gedcom_setting($user_id, $gedid, 'gedcomid')) {
set_user_gedcom_setting($user_id, $gedid, 'gedcomid', null);
echo $gedid, ": ", WT_I18N::translate('Unset GEDCOM ID for '), $user_name, " ";
}
}
}
}
}
break;
case 'listusers':
case 'edituser':
default:
echo
'
',
'',
'
',
'
',
'
user-id
',
'
', WT_I18N::translate('Username'), '
',
'
', WT_I18N::translate('Real name'), '
',
'
', WT_I18N::translate('Email'), '
',
'
', /* COLSPAN does not work? */
'
', WT_I18N::translate('Language'), '
',
'
date_registered
',
'
', WT_I18N::translate('Date registered'), '
',
'
last_login
',
'
', WT_I18N::translate('Last logged in'), '
',
'
', WT_I18N::translate('Verified'), '
',
'
', WT_I18N::translate('Approved'), '
',
'
',
'
',
'',
'',
'',
'
';
$controller
->addExternalJavaScript(WT_STATIC_URL.'js/jquery/jquery.dataTables.min.js')
->addInlineJavaScript('
var oTable = jQuery("#list").dataTable({
"sDom": \'<"H"pf<"dt-clear">irl>t<"F"pl>\',
"oLanguage": {
"sLengthMenu": "'./* I18N: Display %s [records per page], %s is a placeholder for listbox containing numeric options */ WT_I18N::translate('Display %s', '').'",
"sZeroRecords": "'.WT_I18N::translate('No records to display').'",
"sInfo": "'./* I18N: %s are placeholders for numbers */ WT_I18N::translate('Showing %1$s to %2$s of %3$s', '_START_', '_END_', '_TOTAL_').'",
"sInfoEmpty": "'./* I18N: %s are placeholders for numbers */ WT_I18N::translate('Showing %1$s to %2$s of %3$s', '0', '0', '0').'",
"sInfoFiltered": "'./* I18N: %s is a placeholder for a number */ WT_I18N::translate('(filtered from %s total entries)', '_MAX_').'",
"sSearch": "'.WT_I18N::translate('Filter').'",
"oPaginate": {
"sFirst": "'./* I18N: button label, first page */ WT_I18N::translate('first').'",
"sLast": "'./* I18N: button label, last page */ WT_I18N::translate('last').'",
"sNext": "'./* I18N: button label, next page */ WT_I18N::translate('next').'",
"sPrevious": "'./* I18N: button label, previous page */ WT_I18N::translate('previous').'"
}
},
"bProcessing" : true,
"bServerSide" : true,
"sAjaxSource" : "'.WT_SCRIPT_NAME.'?action=loadrows",
"bJQueryUI": true,
"bAutoWidth":false,
"iDisplayLength": '.get_user_setting(WT_USER_ID, 'admin_users_page_size', 10).',
"sPaginationType": "full_numbers",
"aaSorting": [[2,"asc"]],
"aoColumns": [
/* details */ { bSortable:false, sClass:"icon-open" },
/* user-id */ { bVisible:false },
/* user_name */ null,
/* real_name */ null,
/* email */ null,
/* email link */ { bSortable:false },
/* language */ null,
/* registered (sort) */ { bVisible:false },
/* registered */ { iDataSort:7 },
/* last_login (sort) */ { bVisible:false },
/* last_login */ { iDataSort:9 },
/* verified */ { sClass:"center" },
/* approved */ { sClass:"center" },
/* delete */ { bSortable:false }
],
"fnDrawCallback": function() {
// Our JSON responses include JavaScript as well as HTML. This does not get
// executed (except for some versions of Firefox?). So, extract it, and add
// it to its own DOM element
jQuery("#list script").each(function() {
var script=document.createElement("script");
script.type="text/javascript";
jQuery("#list script").appendTo("body");
document.body.appendChild(script);
}).remove();
}
});
/* When clicking on the +/- icon, we expand/collapse the details block */
jQuery("#list tbody td.icon-close").live("click", function () {
var nTr=this.parentNode;
jQuery(this).removeClass("icon-close");
oTable.fnClose(nTr);
jQuery(this).addClass("icon-open");
});
jQuery("#list tbody td.icon-open").live("click", function () {
var nTr=this.parentNode;
jQuery(this).removeClass("icon-open");
var aData=oTable.fnGetData(nTr);
jQuery.get("'.WT_SCRIPT_NAME.'?action=load1row&user_id="+aData[1], function(data) {
oTable.fnOpen(nTr, data, "details");
});
jQuery(this).addClass("icon-close");
});
');
/* Filter immediately for single user name */
if ($action=='edituser') {
$username=safe_GET('username');
$controller->addInlineJavaScript('oTable.fnFilter("'.$username.'");');
}
break;
}