restrictAccess(Auth::isAdmin()) ->setPageTitle(WT_I18N::translate('User administration')); require_once WT_ROOT.'includes/functions/functions_edit.php'; // Valid values for form variables $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 = WT_Filter::get('action', null, 'listusers'); $usrlang = WT_Filter::post('usrlang', implode('|', array_keys(WT_I18N::installed_languages())), WT_LOCALE); $username = WT_Filter::post('username', WT_REGEX_USERNAME); $filter = WT_Filter::post('filter'); $ged = WT_Filter::post('ged'); // Extract form variables $realname = WT_Filter::post('realname' ); $pass1 = WT_Filter::post('pass1', WT_REGEX_PASSWORD); $pass2 = WT_Filter::post('pass2', WT_REGEX_PASSWORD); $emailaddress = WT_Filter::postEmail('emailaddress'); $user_theme = WT_Filter::post('user_theme', implode('|', $ALL_THEME_DIRS)); $user_language = WT_Filter::post('user_language', implode('|', array_keys(WT_I18N::installed_languages())), WT_LOCALE); $new_contact_method = WT_Filter::post('new_contact_method'); $new_comment = WT_Filter::post('new_comment'); $new_auto_accept = WT_Filter::postBool('new_auto_accept'); $canadmin = WT_Filter::postBool('canadmin'); $visibleonline = WT_Filter::postBool('visibleonline'); $editaccount = WT_Filter::postBool('editaccount'); $verified = WT_Filter::postBool('verified'); $verified_by_admin = WT_Filter::postBool('verified_by_admin'); switch ($action) { case 'loadrows': // Generate an AJAX/JSON response for datatables to load a block of rows $search = WT_Filter::get('search'); $search = $search['value']; $start = WT_Filter::getInteger('start'); $length = WT_Filter::getInteger('length'); $WHERE=" WHERE u.user_id>0"; $ARGS=array(); if ($search) { $WHERE.= " AND (". " user_name LIKE CONCAT('%', ?, '%') OR " . " real_name LIKE CONCAT('%', ?, '%') OR " . " email LIKE CONCAT('%', ?, '%'))"; $ARGS=array($search, $search, $search); } Auth::user()->setPreference('admin_users_page_size', $length); if ($length > 0) { $LIMIT = " LIMIT " . $start . ',' . $length; } else { $LIMIT = ""; } $order = WT_Filter::get('order'); if ($order) { $ORDER_BY=' ORDER BY '; for ($i = 0; $i < count($order); ++$i) { if ($i > 0) { $ORDER_BY .= ','; } // Datatables numbers columns 0, 1, 2, ... // MySQL numbers columns 1, 2, 3, ... switch ($order[$i]['dir']) { case 'asc': $ORDER_BY .= (1 + $order[$i]['column']) . ' ASC '; break; case 'desc': $ORDER_BY .= (1 + $order[$i]['column']) . ' DESC '; break; } } } else { $ORDER_BY = '1 ASC'; } $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. $data=WT_DB::prepare($sql)->execute($ARGS)->fetchAll(PDO::FETCH_NUM); // Reformat various columns for display foreach ($data as &$datum) { $datum[0]=' '; // $aData[1] is the user ID $user_id =$datum[1]; $user_name=$datum[2]; $datum[2]=edit_field_inline('user-user_name-'.$user_id, $datum[2]); $datum[3]=edit_field_inline('user-real_name-'.$user_id, $datum[3]); $datum[4]=edit_field_inline('user-email-'. $user_id, $datum[4]); // $aData[5] is a link to an email icon if ($user_id != WT_USER_ID) { $datum[5]=''; } $datum[6]=edit_field_language_inline('user_setting-'.$user_id.'-language', $datum[6]); // $aData[7] is the sortable registration timestamp $datum[8]=$datum[8] ? format_timestamp($datum[8]) : ''; if (date("U") - $datum[7] > 604800 && !$datum[11]) { $datum[8]=''.$datum[8].''; } // $aData[9] is the sortable last-login timestamp if ($datum[9]) { $datum[10]=format_timestamp($datum[9]).'
'.WT_I18N::time_ago(WT_TIMESTAMP - $datum[9]); } else { $datum[10]=WT_I18N::translate('Never'); } $datum[11]=edit_field_yes_no_inline('user_setting-'.$user_id.'-verified-', $datum[11]); $datum[12]=edit_field_yes_no_inline('user_setting-'.$user_id.'-verified_by_admin-', $datum[12]); // Add extra column for "delete" action if ($user_id != WT_USER_ID) { $datum[13]='
'; } else { // Do not delete ourself! $datum[13]=''; } } // Total filtered/unfiltered rows $recordsFiltered = WT_DB::prepare("SELECT FOUND_ROWS()")->fetchOne(); $recordsTotal = User::count(); Zend_Session::writeClose(); header('Content-type: application/json'); echo json_encode(array( // See http://www.datatables.net/usage/server-side 'draw' => WT_Filter::getInteger('draw'), // String, but always an integer 'recordsTotal' => $recordsTotal, 'recordsFiltered' => $recordsFiltered, 'data' => $data )); exit; case 'load1row': // Generate an AJAX response for datatables to load expanded row $user_id = WT_Filter::getInteger('user_id'); $user = User::find($user_id); Zend_Session::writeClose(); header('Content-type: text/html; charset=UTF-8'); echo '

', WT_I18N::translate('Details'), '

'; echo '
'; echo '
', WT_I18N::translate('Administrator'), '
'; echo '
', edit_field_yes_no_inline('user_setting-'.$user_id.'-canadmin', $user->getPreference('canadmin')), '
'; echo '
', WT_I18N::translate('Password'), '
'; echo '
', edit_field_inline('user-password-'.$user_id, ''), '
'; echo '
', WT_I18N::translate('Preferred contact method'), '
'; echo '
', edit_field_contact_inline('user_setting-'.$user_id.'-contactmethod', $user->getPreference('contactmethod')), '
'; echo '
', WT_I18N::translate('Allow this user to edit his account information'), '
'; echo '
', edit_field_yes_no_inline('user_setting-'.$user_id.'-editaccount', $user->getPreference('editaccount')), '
'; echo '
', WT_I18N::translate('Automatically approve changes made by this user'), '
'; echo '
', edit_field_yes_no_inline('user_setting-'.$user_id.'-auto_accept', $user->getPreference('auto_accept')), '
'; echo '
', WT_I18N::translate('Theme'), '
'; echo '
', select_edit_control_inline('user_setting-'.$user_id.'-theme', array_flip(get_theme_names()), WT_I18N::translate(''), $user->getPreference('theme')), '
'; echo '
', WT_I18N::translate('Visible to other users when online'), '
'; echo '
', edit_field_yes_no_inline('user_setting-'.$user_id.'-visibleonline', $user->getPreference('visibleonline')), '
'; echo '
', WT_I18N::translate('Comments'), '
'; echo '
', edit_field_inline('user_setting-'.$user_id.'-comment', $user->getPreference('comment')), '
'; echo '
', WT_I18N::translate('My page'), '
'; echo '
', WT_I18N::translate('Change the blocks on this page'), '
'; // Masquerade as others users - but not other administrators if (!Auth::isAdmin($user)) { echo '
', /* I18N: Pretend to be another user, by logging in as them */ WT_I18N::translate('Masquerade as this user'), '
'; echo '
', /* I18N: verb: pretend to be someone else */ WT_I18N::translate('masquerade'), '
'; } echo '
'; // Column One - details echo '
', '

', WT_I18N::translate('Family tree access and settings'), '

', '', '', '', '', '', '', ''; foreach (WT_Tree::getAll() as $tree) { echo ''; } echo '
', WT_I18N::translate('Family tree'), '', WT_I18N::translate('Default individual'), help_link('default_individual'), '', WT_I18N::translate('Individual record'), help_link('useradmin_gedcomid'), '', WT_I18N::translate('Role'), help_link('role'), '', WT_I18N::translate('Restrict to immediate family'), help_link('RELATIONSHIP_PATH_LENGTH'), '
', $tree->tree_title_html, //Pedigree root person '', // TODO: autocomplete/find/etc. for this field edit_field_inline('user_gedcom_setting-'.$user_id.'-'.$tree->tree_id.'-rootid', $tree->getUserPreference($user, 'rootid')), '', // TODO: autocomplete/find/etc. for this field edit_field_inline('user_gedcom_setting-'.$user_id.'-'.$tree->tree_id.'-gedcomid', $tree->getUserPreference($user, 'gedcomid')), '', select_edit_control_inline('user_gedcom_setting-'.$user_id.'-'.$tree->tree_id.'-canedit', $ALL_EDIT_OPTIONS, null, $tree->getUserPreference($user, 'canedit')), '', select_edit_control_inline('user_gedcom_setting-'.$user_id.'-'.$tree->tree_id.'-RELATIONSHIP_PATH_LENGTH', array(0=>WT_I18N::translate('no'), 1=>1, 2=>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9, 10=>10), null, $tree->getUserPreference($user, 'RELATIONSHIP_PATH_LENGTH')), '
'; exit; case 'createuser': if (!WT_Filter::checkCsrf()) { $action='createform'; } elseif (User::findByIdentifier($username)) { WT_FlashMessages::addMessage(WT_I18N::translate('Duplicate user name. A user with that user name already exists. Please choose another user name.')); $action='createform'; } elseif (User::findByIdentifier($emailaddress)) { WT_FlashMessages::addMessage(WT_I18N::translate('Duplicate email address. A user with that email already exists.')); $action='createform'; } elseif ($pass1!=$pass2) { WT_FlashMessages::addMessage(WT_I18N::translate('Passwords do not match.')); $action='createform'; } else { $user = User::create($username, $realname, $emailaddress, $pass1); $user ->setPreference('reg_timestamp', date('U')) ->setPreference('sessiontime', '0') ->setPreference('theme', $user_theme) ->setPreference('language', $user_language) ->setPreference('contactmethod', $new_contact_method) ->setPreference('comment', $new_comment) ->setPreference('auto_accept', $new_auto_accept) ->setPreference('canadmin', $canadmin) ->setPreference('visibleonline', $visibleonline) ->setPreference('editaccount', $editaccount) ->setPreference('verified', $verified) ->setPreference('verified_by_admin', $verified_by_admin); foreach (WT_Tree::getAll() as $tree) { $tree->setUserPreference($user, 'gedcomid', WT_Filter::post('gedcomid'.$tree->tree_id, WT_REGEX_XREF)); $tree->setUserPreference($user, 'rootid', WT_Filter::post('rootid'.$tree->tree_id, WT_REGEX_XREF)); $tree->setUserPreference($user, 'canedit', WT_Filter::post('canedit'.$tree->tree_id, implode('|', array_keys($ALL_EDIT_OPTIONS)))); if (WT_Filter::post('gedcomid'.$tree->tree_id, WT_REGEX_XREF)) { $tree->setUserPreference($user, 'RELATIONSHIP_PATH_LENGTH', WT_Filter::postInteger('RELATIONSHIP_PATH_LENGTH'.$tree->tree_id, 0, 10, 0)); } else { // Do not allow a path length to be set if the individual ID is not $tree->setUserPreference($user, 'RELATIONSHIP_PATH_LENGTH', null); } } Log::addAuthenticationLog("User ->{$username}<- created"); header('Location: ' . WT_SERVER_NAME . WT_SCRIPT_PATH . WT_SCRIPT_NAME); WT_Session::writeClose(); exit; } } $controller->pageHeader(); switch ($action) { case 'createform': $controller ->addExternalJavascript(WT_STATIC_URL . 'js/autocomplete.js') ->addInlineJavascript('autocomplete();'); init_calendar_popup(); $controller->addInlineJavascript(' function checkform(frm) { if (frm.username.value=="") { alert("'.WT_I18N::translate('You must enter a user name.').'"); frm.username.focus(); return false; } if (frm.realname.value=="") { alert("'.WT_I18N::translate('You must enter a real name.').'"); frm.realname.focus(); return false; } if (frm.pass1.value=="") { alert("'.WT_I18N::translate('You must enter a password.').'"); frm.pass1.focus(); return false; } if (frm.emailaddress.value=="") { alert("'.WT_I18N::translate('You must enter an email address.').'"); frm.emailaddress.focus(); return false; } if (frm.pass2.value=="") { alert("'.WT_I18N::translate('You must confirm the password.').'"); frm.pass2.focus(); return false; } if (frm.pass1.value.length < 6) { alert("'.WT_I18N::translate('Passwords must contain at least 6 characters.').'"); frm.pass1.value = ""; frm.pass2.value = ""; frm.pass1.focus(); return false; } return true; } 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("'.WT_I18N::translate('You must specify an individual record before you can restrict the user to their immediate family.').'"); jQuery(this).val(""); } }); function regex_quote(str) { return str.replace(/[\\\\.?+*()[\](){}|]/g, "\\\\$&"); } '); echo '
', WT_Filter::getCsrf(), ' '; if (WT_Site::getPreference('ALLOW_USER_THEMES')) { echo ''; } echo ''; if (Auth::isAdmin()) { echo ''; } echo '
', WT_I18N::translate('Real name'), help_link('real_name'), ' ', WT_I18N::translate('Administrator'), help_link('role'), '
', WT_I18N::translate('Username'), help_link('username'), ' ', WT_I18N::translate('Approved by administrator'), help_link('useradmin_verification'), '
', WT_I18N::translate('Email address'), help_link('email'), ' ', WT_I18N::translate('Email verified'), help_link('useradmin_verification'), '
', WT_I18N::translate('Password'), help_link('password'), ' ', WT_I18N::translate('Automatically approve changes made by this user'), help_link('useradmin_auto_accept'), '
', WT_I18N::translate('Confirm password'), help_link('password_confirm'), ' ', WT_I18N::translate('Allow this user to edit his account information'), help_link('useradmin_editaccount'), '
', WT_I18N::translate('Preferred contact method'), ' '; echo edit_field_contact('new_contact_method', $new_contact_method); echo ' ', WT_I18N::translate('Visible to other users when online'), help_link('useradmin_visibleonline'), '
', WT_I18N::translate('Language'), ' ', edit_field_language('user_language', $user_language), '', WT_I18N::translate('Theme'), help_link('THEME'), '
', WT_I18N::translate('Admin comments on user'), '
', WT_I18N::translate('Family tree access and settings'), '
'; foreach (WT_Tree::getAll() as $tree) { echo '', '', //Pedigree root person '', // GEDCOM INDI Record ID '', '', //Relationship path '', ''; } echo '
', WT_I18N::translate('Family tree'), ' ', WT_I18N::translate('Default individual'), help_link('default_individual'), ' ', WT_I18N::translate('Individual record'), help_link('useradmin_gedcomid'), ' ', WT_I18N::translate('Role'), help_link('role'), ' ', WT_I18N::translate('Restrict to immediate family'), help_link('RELATIONSHIP_PATH_LENGTH'), '
', $tree->tree_title_html, ''; $varname='rootid'.$tree->tree_id; echo ' ', print_findindi_link($varname, '', $tree->tree_name), ''; $varname='gedcomid'.$tree->tree_id; echo ' ', print_findindi_link($varname, '', $tree->tree_name), ''; $varname='canedit'.$tree->tree_id; echo '', ''; $varname = 'RELATIONSHIP_PATH_LENGTH'.$tree->tree_id; echo '', '
'; break; case 'cleanup': ?>
"; echo ""; ?> getPreference('sessiontime') == "0") { $datelogin = (int)$user->getPreference('reg_timestamp'); } else { $datelogin = (int)$user->getPreference('sessiontime'); } if ((mktime(0, 0, 0, (int)date("m")-$month, (int)date("d"), (int)date("Y")) > $datelogin) && $user->getPreference('verified') && $user->getPreference('verified_by_admin')) { ?>getPreference('reg_timestamp')) > 604800) && !$user->getPreference('verified')) { ?>getPreference('verified_by_admin') && $user->getPreference('verified')) { ?>"; } ?>
", WT_I18N::translate('Number of months since the last login for a user’s account to be considered inactive: '), "
getUserName()), " -

", WT_Filter::escapeHtml($user->getRealName()), "

", WT_I18N::translate('User’s account has been inactive too long: '); echo timestamp_to_gedcom_date($datelogin)->Display(false); $ucnt++; ?>
getUserName()), " - ", WT_Filter::escapeHtml($user->getRealName()), ":  ", WT_I18N::translate('User didn’t verify within 7 days.'); $ucnt++; ?>
getUserName()), " - ", WT_Filter::escapeHtml($user->getRealName()), ":  ", WT_I18N::translate('User not verified by administrator.'); ?>
"; echo WT_I18N::translate('Nothing found to cleanup'), "

0) { ?>  

getUserId()) == '1') { Log::addAuthenticationLog('Deleted user: ' . $user->getUserName()); echo WT_I18N::translate('Deleted user: '), $user->getUserName(), '
'; $user->delete(); } } break; case 'listusers': default: echo '', '', '', '', '', '', '', '', '', /* COLSPAN does not work? */ '', '', '', '', '', '', '', '', '', '', '', '', '
user-id ', WT_I18N::translate('Username'), '', WT_I18N::translate('Real name'), '', WT_I18N::translate('Email'), ' ', 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_JQUERY_DATATABLES_URL) ->addExternalJavascript(WT_JQUERY_JEDITABLE_URL) ->addInlineJavascript(' var oTable = jQuery("#list").dataTable({ dom: \'<"H"pf<"dt-clear">irl>t<"F"pl>\', '.WT_I18N::datatablesI18N().', processing: true, serverSide: true, ajax: "'.WT_SCRIPT_NAME.'?action=loadrows", jQueryUI: true, autoWidth: false, pageLength: ' . Auth::user()->getPreference('admin_users_page_size', 10).', pagingType: "full_numbers", sorting: [[2,"asc"]], columns: [ /* details */ { sortable: false, class: "icon-open" }, /* user-id */ { visible: false }, /* user_name */ null, /* real_name */ null, /* email */ null, /* email link */ { sortable: false }, /* language */ null, /* registered (sort) */ { visible: false }, /* registered */ { dataSort: 7 }, /* last_login (sort) */ { visible: false }, /* last_login */ { dataSort: 9 }, /* verified */ { class: "center" }, /* approved */ { class: "center" }, /* delete */ { sortable: false } ], "drawCallback": function() { // Our JSON responses include Javascript as well as HTML. This does not get executed automatically… jQuery("#list script").each(function() { eval(this.text); }); } }); /* When clicking on the +/- icon, we expand/collapse the details block */ jQuery("#list tbody").on("click", "td.icon-close", function () { var nTr=this.parentNode; jQuery(this).removeClass("icon-close"); oTable.fnClose(nTr); jQuery(this).addClass("icon-open"); }); jQuery("#list tbody").on("click", "td.icon-open", 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"); }); oTable.fnFilter("'.WT_Filter::get('filter').'"); '); break; }