11ab40613Stracker-user<?php 21ab40613Stracker-user 31ab40613Stracker-user/** 41ab40613Stracker-user * User Settings plugin — admin component. 51ab40613Stracker-user * 61ab40613Stracker-user * Provides an admin-only overview of every user's preferences as a flat, 71ab40613Stracker-user * sortable table: one row per (user x setting), with the columns 81ab40613Stracker-user * Display name | Setting | Value | Changed by | Changed at. 91ab40613Stracker-user * A row's value is the user's explicit choice, or the toggle's default 101ab40613Stracker-user * (marked as such) when they never set one. A filter narrows the table to a 111ab40613Stracker-user * single setting; the table never grows wider as more toggles are added. 121ab40613Stracker-user * 131ab40613Stracker-user * Clicking a display name opens a per-user edit form (Model A+: an admin may 141ab40613Stracker-user * change anyone's preferences). Such a change is stored with the admin as the 151ab40613Stracker-user * recorded actor, and the user can still change it back themselves later. 161ab40613Stracker-user */ 171ab40613Stracker-user 181ab40613Stracker-user// must be run within DokuWiki 191ab40613Stracker-userif (!defined('DOKU_INC')) die(); 201ab40613Stracker-user 211ab40613Stracker-userclass admin_plugin_usersettings extends DokuWiki_Admin_Plugin 221ab40613Stracker-user{ 231ab40613Stracker-user /** @var string[] sort key => row field used for that sort */ 241ab40613Stracker-user protected $sortFields = [ 251ab40613Stracker-user 'name' => 'display_name', 261ab40613Stracker-user 'setting' => 'setting_label', 271ab40613Stracker-user 'value' => 'value_display', 281ab40613Stracker-user 'changedby' => 'changed_by_display', 291ab40613Stracker-user 'changedat' => 'changed_at', 301ab40613Stracker-user ]; 311ab40613Stracker-user 321ab40613Stracker-user // --------------------------------------------------------------------- 331ab40613Stracker-user // Admin plugin metadata 341ab40613Stracker-user // --------------------------------------------------------------------- 351ab40613Stracker-user 361ab40613Stracker-user /** Only administrators may see other users' preferences. */ 371ab40613Stracker-user public function forAdminOnly() 381ab40613Stracker-user { 391ab40613Stracker-user return true; 401ab40613Stracker-user } 411ab40613Stracker-user 421ab40613Stracker-user /** Position in the admin menu. */ 431ab40613Stracker-user public function getMenuSort() 441ab40613Stracker-user { 45*437b34a9Stracker-user return 1000; 461ab40613Stracker-user } 471ab40613Stracker-user 481ab40613Stracker-user /** Admin menu label — distinct from the user menu's "Preferences". */ 491ab40613Stracker-user public function getMenuText($language) 501ab40613Stracker-user { 511ab40613Stracker-user return $this->getLang('admin_menu'); 521ab40613Stracker-user } 531ab40613Stracker-user 541ab40613Stracker-user // --------------------------------------------------------------------- 551ab40613Stracker-user // Component access 561ab40613Stracker-user // --------------------------------------------------------------------- 571ab40613Stracker-user 581ab40613Stracker-user /** @return helper_plugin_usersettings|null */ 591ab40613Stracker-user protected function getHelper() 601ab40613Stracker-user { 611ab40613Stracker-user return plugin_load('helper', 'usersettings'); 621ab40613Stracker-user } 631ab40613Stracker-user 641ab40613Stracker-user /** @return action_plugin_usersettings|null */ 651ab40613Stracker-user protected function getActionPlugin() 661ab40613Stracker-user { 671ab40613Stracker-user return plugin_load('action', 'usersettings'); 681ab40613Stracker-user } 691ab40613Stracker-user 701ab40613Stracker-user // --------------------------------------------------------------------- 711ab40613Stracker-user // Request handling 721ab40613Stracker-user // --------------------------------------------------------------------- 731ab40613Stracker-user 741ab40613Stracker-user /** 751ab40613Stracker-user * Handle a submitted per-user edit form. 761ab40613Stracker-user * 771ab40613Stracker-user * Runs only for admins (DokuWiki's admin dispatcher enforces 781ab40613Stracker-user * forAdminOnly() before this is called). Uses Post/Redirect/Get. 791ab40613Stracker-user */ 801ab40613Stracker-user public function handle() 811ab40613Stracker-user { 821ab40613Stracker-user global $INPUT, $ID; 831ab40613Stracker-user 841ab40613Stracker-user if (!$INPUT->post->bool('usersettings_adminsave')) { 851ab40613Stracker-user return; 861ab40613Stracker-user } 871ab40613Stracker-user if (!checkSecurityToken()) { 881ab40613Stracker-user return; 891ab40613Stracker-user } 901ab40613Stracker-user 911ab40613Stracker-user $this->processAdminSave(); 921ab40613Stracker-user 931ab40613Stracker-user // Post/Redirect/Get back to the overview 941ab40613Stracker-user send_redirect(wl($ID, ['do' => 'admin', 'page' => 'usersettings'], true, '&')); 951ab40613Stracker-user } 961ab40613Stracker-user 971ab40613Stracker-user /** 981ab40613Stracker-user * Validate the target user and store the submitted preferences for them, 991ab40613Stracker-user * recording the acting admin as the actor. Kept redirect-free so it can 1001ab40613Stracker-user * be tested directly. 1011ab40613Stracker-user * 1021ab40613Stracker-user * @return bool 1031ab40613Stracker-user */ 1041ab40613Stracker-user public function processAdminSave() 1051ab40613Stracker-user { 1061ab40613Stracker-user global $INPUT, $auth; 1071ab40613Stracker-user 1081ab40613Stracker-user $target = $INPUT->post->str('edituser'); 1091ab40613Stracker-user $admin = $INPUT->server->str('REMOTE_USER'); 1101ab40613Stracker-user 1111ab40613Stracker-user $userData = ($auth !== null) ? $auth->getUserData($target) : false; 1121ab40613Stracker-user if ($userData === false) { 1131ab40613Stracker-user msg($this->getLang('badidentuser'), -1); 1141ab40613Stracker-user return false; 1151ab40613Stracker-user } 1161ab40613Stracker-user 1171ab40613Stracker-user $action = $this->getActionPlugin(); 1181ab40613Stracker-user $ok = ($action !== null) && $action->saveSubmittedPreferences($target, $admin); 1191ab40613Stracker-user 1201ab40613Stracker-user $name = ($userData['name'] !== '') ? $userData['name'] : $target; 1211ab40613Stracker-user msg( 1221ab40613Stracker-user sprintf($this->getLang($ok ? 'adminsaved' : 'adminsavefail'), hsc($name)), 1231ab40613Stracker-user $ok ? 1 : -1 1241ab40613Stracker-user ); 1251ab40613Stracker-user return $ok; 1261ab40613Stracker-user } 1271ab40613Stracker-user 1281ab40613Stracker-user // --------------------------------------------------------------------- 1291ab40613Stracker-user // Output 1301ab40613Stracker-user // --------------------------------------------------------------------- 1311ab40613Stracker-user 1321ab40613Stracker-user /** 1331ab40613Stracker-user * Render either the overview table or, when an edituser parameter is 1341ab40613Stracker-user * present, the per-user edit form. 1351ab40613Stracker-user */ 1361ab40613Stracker-user public function html() 1371ab40613Stracker-user { 1381ab40613Stracker-user global $INPUT; 1391ab40613Stracker-user 1401ab40613Stracker-user $edituser = $INPUT->get->str('edituser'); 1411ab40613Stracker-user if ($edituser !== '') { 1421ab40613Stracker-user echo $this->renderEditForm($edituser); 1431ab40613Stracker-user } else { 1441ab40613Stracker-user echo $this->renderTable(); 1451ab40613Stracker-user } 1461ab40613Stracker-user } 1471ab40613Stracker-user 1481ab40613Stracker-user // ---- overview table -------------------------------------------------- 1491ab40613Stracker-user 1501ab40613Stracker-user /** 1511ab40613Stracker-user * Build the rows of the overview: one per (user x toggle). 1521ab40613Stracker-user * 1531ab40613Stracker-user * @param array $users [username => userdata] as from $auth->retrieveUsers() 1541ab40613Stracker-user * @param array $toggles registered toggle definitions 1551ab40613Stracker-user * @return array list of row arrays 1561ab40613Stracker-user */ 1571ab40613Stracker-user public function buildRows(array $users, array $toggles) 1581ab40613Stracker-user { 1591ab40613Stracker-user $helper = $this->getHelper(); 1601ab40613Stracker-user if ($helper === null) { 1611ab40613Stracker-user return []; 1621ab40613Stracker-user } 1631ab40613Stracker-user 1641ab40613Stracker-user $rows = []; 1651ab40613Stracker-user foreach ($users as $username => $userData) { 1661ab40613Stracker-user $displayName = (!empty($userData['name'])) ? $userData['name'] : $username; 1671ab40613Stracker-user $stored = $helper->loadUserData($username); 1681ab40613Stracker-user 1691ab40613Stracker-user foreach ($toggles as $key => $def) { 1701ab40613Stracker-user if (isset($stored[$key]) && array_key_exists('value', $stored[$key])) { 1711ab40613Stracker-user $value = $stored[$key]['value']; 1721ab40613Stracker-user $changedBy = $stored[$key]['changed_by'] ?? ''; 1731ab40613Stracker-user $changedAt = (int) ($stored[$key]['changed_at'] ?? 0); 1741ab40613Stracker-user $isDefault = false; 1751ab40613Stracker-user } else { 1761ab40613Stracker-user $value = $def['default']; 1771ab40613Stracker-user $changedBy = ''; 1781ab40613Stracker-user $changedAt = 0; 1791ab40613Stracker-user $isDefault = true; 1801ab40613Stracker-user } 1811ab40613Stracker-user 1821ab40613Stracker-user $rows[] = [ 1831ab40613Stracker-user 'user' => $username, 1841ab40613Stracker-user 'display_name' => $displayName, 1851ab40613Stracker-user 'setting_key' => $key, 1861ab40613Stracker-user 'setting_label' => $def['label'], 1871ab40613Stracker-user 'value_display' => $this->displayValue($def, $value), 1881ab40613Stracker-user 'is_default' => $isDefault, 1891ab40613Stracker-user 'changed_by_display' => $isDefault ? '' : $this->resolveActor($changedBy, $users), 1901ab40613Stracker-user 'changed_at' => $changedAt, 1911ab40613Stracker-user ]; 1921ab40613Stracker-user } 1931ab40613Stracker-user } 1941ab40613Stracker-user return $rows; 1951ab40613Stracker-user } 1961ab40613Stracker-user 1971ab40613Stracker-user /** 1981ab40613Stracker-user * Sort overview rows by the given column and direction. 1991ab40613Stracker-user * 2001ab40613Stracker-user * @param array $rows 2011ab40613Stracker-user * @param string $sort one of the keys of $this->sortFields 2021ab40613Stracker-user * @param string $dir 'asc' or 'desc' 2031ab40613Stracker-user * @return array 2041ab40613Stracker-user */ 2051ab40613Stracker-user public function sortRows(array $rows, $sort, $dir) 2061ab40613Stracker-user { 2071ab40613Stracker-user $field = $this->sortFields[$sort] ?? 'display_name'; 2081ab40613Stracker-user 2091ab40613Stracker-user usort($rows, function ($a, $b) use ($field) { 2101ab40613Stracker-user if ($field === 'changed_at') { 2111ab40613Stracker-user return $a[$field] <=> $b[$field]; 2121ab40613Stracker-user } 2131ab40613Stracker-user return strcasecmp((string) $a[$field], (string) $b[$field]); 2141ab40613Stracker-user }); 2151ab40613Stracker-user 2161ab40613Stracker-user if ($dir === 'desc') { 2171ab40613Stracker-user $rows = array_reverse($rows); 2181ab40613Stracker-user } 2191ab40613Stracker-user return $rows; 2201ab40613Stracker-user } 2211ab40613Stracker-user 2221ab40613Stracker-user /** 2231ab40613Stracker-user * Human-readable value of a toggle: On/Off for a checkbox, the option 2241ab40613Stracker-user * label for a select. 2251ab40613Stracker-user * 2261ab40613Stracker-user * @param array $def 2271ab40613Stracker-user * @param mixed $value 2281ab40613Stracker-user * @return string 2291ab40613Stracker-user */ 2301ab40613Stracker-user public function displayValue(array $def, $value) 2311ab40613Stracker-user { 2321ab40613Stracker-user if ($def['type'] === 'select') { 2331ab40613Stracker-user if (isset($def['options'][$value])) { 2341ab40613Stracker-user return (string) $def['options'][$value]; 2351ab40613Stracker-user } 2361ab40613Stracker-user return (string) $value; // stored value no longer a defined option 2371ab40613Stracker-user } 2381ab40613Stracker-user return $this->getLang(empty($value) ? 'val_off' : 'val_on'); 2391ab40613Stracker-user } 2401ab40613Stracker-user 2411ab40613Stracker-user /** 2421ab40613Stracker-user * Resolve an actor username to a display name, falling back to the raw 2431ab40613Stracker-user * username when the actor is not (or no longer) a known user. 2441ab40613Stracker-user * 2451ab40613Stracker-user * @param string $actor 2461ab40613Stracker-user * @param array $users [username => userdata] 2471ab40613Stracker-user * @return string 2481ab40613Stracker-user */ 2491ab40613Stracker-user protected function resolveActor($actor, array $users) 2501ab40613Stracker-user { 2511ab40613Stracker-user if ($actor === '') { 2521ab40613Stracker-user return ''; 2531ab40613Stracker-user } 2541ab40613Stracker-user if (isset($users[$actor]) && !empty($users[$actor]['name'])) { 2551ab40613Stracker-user return $users[$actor]['name']; 2561ab40613Stracker-user } 2571ab40613Stracker-user return $actor; 2581ab40613Stracker-user } 2591ab40613Stracker-user 2601ab40613Stracker-user /** 2611ab40613Stracker-user * Render the overview table. 2621ab40613Stracker-user * 2631ab40613Stracker-user * @return string 2641ab40613Stracker-user */ 2651ab40613Stracker-user protected function renderTable() 2661ab40613Stracker-user { 2671ab40613Stracker-user global $INPUT, $auth; 2681ab40613Stracker-user 2691ab40613Stracker-user $helper = $this->getHelper(); 2701ab40613Stracker-user $toggles = $helper ? $helper->getRegisteredToggles() : []; 2711ab40613Stracker-user 2721ab40613Stracker-user $html = '<div class="plugin_usersettings_admin">'; 2731ab40613Stracker-user $html .= '<h1>' . hsc($this->getLang('admin_heading')) . '</h1>'; 2741ab40613Stracker-user 2751ab40613Stracker-user if (empty($toggles)) { 2761ab40613Stracker-user return $html . '<p>' . hsc($this->getLang('notoggles')) . '</p></div>'; 2771ab40613Stracker-user } 2781ab40613Stracker-user 2791ab40613Stracker-user $users = ($auth !== null) ? $auth->retrieveUsers(0, 0) : []; 2801ab40613Stracker-user if (empty($users)) { 2811ab40613Stracker-user return $html . '<p>' . hsc($this->getLang('nousers')) . '</p></div>'; 2821ab40613Stracker-user } 2831ab40613Stracker-user 2841ab40613Stracker-user // request parameters (sort links and the filter form are GET) 2851ab40613Stracker-user $sort = $INPUT->get->str('sort', 'name'); 2861ab40613Stracker-user $dir = ($INPUT->get->str('dir') === 'desc') ? 'desc' : 'asc'; 2871ab40613Stracker-user $filter = $INPUT->get->str('filter'); 2881ab40613Stracker-user if (!isset($this->sortFields[$sort])) { 2891ab40613Stracker-user $sort = 'name'; 2901ab40613Stracker-user } 2911ab40613Stracker-user if ($filter !== '' && !isset($toggles[$filter])) { 2921ab40613Stracker-user $filter = ''; 2931ab40613Stracker-user } 2941ab40613Stracker-user 2951ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('admin_intro')) . '</p>'; 2961ab40613Stracker-user $html .= $this->renderFilter($toggles, $sort, $dir, $filter); 2971ab40613Stracker-user 2981ab40613Stracker-user // rows 2991ab40613Stracker-user $rows = $this->buildRows($users, $toggles); 3001ab40613Stracker-user if ($filter !== '') { 3011ab40613Stracker-user $rows = array_values(array_filter($rows, function ($r) use ($filter) { 3021ab40613Stracker-user return $r['setting_key'] === $filter; 3031ab40613Stracker-user })); 3041ab40613Stracker-user } 3051ab40613Stracker-user $rows = $this->sortRows($rows, $sort, $dir); 3061ab40613Stracker-user 3071ab40613Stracker-user // table 3081ab40613Stracker-user $html .= '<table class="inline plugin_usersettings_table">'; 3091ab40613Stracker-user $html .= '<thead><tr>'; 3101ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_name'), 'name', $sort, $dir, $filter); 3111ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_setting'), 'setting', $sort, $dir, $filter); 3121ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_value'), 'value', $sort, $dir, $filter); 3131ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_changedby'), 'changedby', $sort, $dir, $filter); 3141ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_changedat'), 'changedat', $sort, $dir, $filter); 3151ab40613Stracker-user $html .= '</tr></thead><tbody>'; 3161ab40613Stracker-user 3171ab40613Stracker-user foreach ($rows as $row) { 3181ab40613Stracker-user $rowClass = $row['is_default'] ? ' class="us-default-row"' : ''; 3191ab40613Stracker-user $editUrl = $this->pageURL(['edituser' => $row['user']]); 3201ab40613Stracker-user 3211ab40613Stracker-user $html .= '<tr' . $rowClass . '>'; 3221ab40613Stracker-user $html .= '<td><a href="' . $editUrl . '">' . hsc($row['display_name']) . '</a></td>'; 3231ab40613Stracker-user $html .= '<td>' . hsc($row['setting_label']) . '</td>'; 3241ab40613Stracker-user $html .= '<td>' . hsc($row['value_display']) . '</td>'; 3251ab40613Stracker-user $html .= '<td>' . ($row['is_default'] 3261ab40613Stracker-user ? '<span class="us-default-mark">' . hsc($this->getLang('bydefault')) . '</span>' 3271ab40613Stracker-user : hsc($row['changed_by_display'])) . '</td>'; 3281ab40613Stracker-user $html .= '<td>' . ($row['changed_at'] > 0 ? hsc(dformat($row['changed_at'])) : '—') . '</td>'; 3291ab40613Stracker-user $html .= '</tr>'; 3301ab40613Stracker-user } 3311ab40613Stracker-user 3321ab40613Stracker-user $html .= '</tbody></table>'; 3331ab40613Stracker-user return $html . '</div>'; 3341ab40613Stracker-user } 3351ab40613Stracker-user 3361ab40613Stracker-user /** 3371ab40613Stracker-user * Render the setting filter (a small GET form). 3381ab40613Stracker-user * 3391ab40613Stracker-user * @param array $toggles 3401ab40613Stracker-user * @param string $sort 3411ab40613Stracker-user * @param string $dir 3421ab40613Stracker-user * @param string $filter currently selected setting key 3431ab40613Stracker-user * @return string 3441ab40613Stracker-user */ 3451ab40613Stracker-user protected function renderFilter(array $toggles, $sort, $dir, $filter) 3461ab40613Stracker-user { 3471ab40613Stracker-user global $ID; 3481ab40613Stracker-user 3491ab40613Stracker-user // GET forms drop the action URL's query string, so every parameter 3501ab40613Stracker-user // travels as an explicit field — this also survives URL rewriting. 3511ab40613Stracker-user $html = '<form class="us-filter" method="get" action="' . DOKU_BASE . DOKU_SCRIPT . '">'; 3521ab40613Stracker-user $html .= '<input type="hidden" name="id" value="' . hsc($ID) . '" />'; 3531ab40613Stracker-user $html .= '<input type="hidden" name="do" value="admin" />'; 3541ab40613Stracker-user $html .= '<input type="hidden" name="page" value="usersettings" />'; 3551ab40613Stracker-user $html .= '<input type="hidden" name="sort" value="' . hsc($sort) . '" />'; 3561ab40613Stracker-user $html .= '<input type="hidden" name="dir" value="' . hsc($dir) . '" />'; 3571ab40613Stracker-user 3581ab40613Stracker-user $html .= '<label>' . hsc($this->getLang('filter_label')) . ' '; 3591ab40613Stracker-user $html .= '<select name="filter">'; 3601ab40613Stracker-user $html .= '<option value="">' . hsc($this->getLang('filter_all')) . '</option>'; 3611ab40613Stracker-user foreach ($toggles as $key => $def) { 3621ab40613Stracker-user $selected = ($filter === $key) ? ' selected="selected"' : ''; 3631ab40613Stracker-user $html .= '<option value="' . hsc($key) . '"' . $selected . '>' 3641ab40613Stracker-user . hsc($def['label']) . '</option>'; 3651ab40613Stracker-user } 3661ab40613Stracker-user $html .= '</select></label> '; 3671ab40613Stracker-user $html .= '<button type="submit">' . hsc($this->getLang('filter_apply')) . '</button>'; 3681ab40613Stracker-user return $html . '</form>'; 3691ab40613Stracker-user } 3701ab40613Stracker-user 3711ab40613Stracker-user /** 3721ab40613Stracker-user * Render one sortable column header. 3731ab40613Stracker-user * 3741ab40613Stracker-user * @param string $label 3751ab40613Stracker-user * @param string $col sort key for this column 3761ab40613Stracker-user * @param string $sort currently active sort key 3771ab40613Stracker-user * @param string $dir currently active direction 3781ab40613Stracker-user * @param string $filter currently active filter (preserved in the link) 3791ab40613Stracker-user * @return string 3801ab40613Stracker-user */ 3811ab40613Stracker-user protected function sortHeader($label, $col, $sort, $dir, $filter) 3821ab40613Stracker-user { 3831ab40613Stracker-user // clicking the active column flips direction; others start ascending 3841ab40613Stracker-user $newDir = ($sort === $col && $dir === 'asc') ? 'desc' : 'asc'; 3851ab40613Stracker-user $arrow = ''; 3861ab40613Stracker-user if ($sort === $col) { 3871ab40613Stracker-user $arrow = ($dir === 'asc') ? " \u{25B2}" : " \u{25BC}"; 3881ab40613Stracker-user } 3891ab40613Stracker-user 3901ab40613Stracker-user $url = $this->pageURL(['sort' => $col, 'dir' => $newDir, 'filter' => $filter]); 3911ab40613Stracker-user return '<th><a href="' . $url . '">' . hsc($label) . $arrow . '</a></th>'; 3921ab40613Stracker-user } 3931ab40613Stracker-user 3941ab40613Stracker-user // ---- per-user edit form --------------------------------------------- 3951ab40613Stracker-user 3961ab40613Stracker-user /** 3971ab40613Stracker-user * Render the edit form for one user's preferences. 3981ab40613Stracker-user * 3991ab40613Stracker-user * @param string $user 4001ab40613Stracker-user * @return string 4011ab40613Stracker-user */ 4021ab40613Stracker-user protected function renderEditForm($user) 4031ab40613Stracker-user { 4041ab40613Stracker-user global $auth, $ID; 4051ab40613Stracker-user 4068f16c88bStracker-user $html = '<div class="plugin_usersettings_admin plugin_usersettings">'; 4071ab40613Stracker-user 4081ab40613Stracker-user $userData = ($auth !== null) ? $auth->getUserData($user) : false; 4091ab40613Stracker-user if ($userData === false) { 4101ab40613Stracker-user $html .= '<h1>' . hsc($this->getLang('admin_heading')) . '</h1>'; 4111ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('badidentuser')) . '</p>'; 4121ab40613Stracker-user $html .= '<p><a href="' . $this->pageURL() . '">' 4131ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a></p>'; 4141ab40613Stracker-user return $html . '</div>'; 4151ab40613Stracker-user } 4161ab40613Stracker-user 4171ab40613Stracker-user $displayName = ($userData['name'] !== '') ? $userData['name'] : $user; 4181ab40613Stracker-user $html .= '<h1>' . hsc(sprintf($this->getLang('edit_heading'), $displayName)) . '</h1>'; 4191ab40613Stracker-user 4201ab40613Stracker-user $helper = $this->getHelper(); 4211ab40613Stracker-user $action = $this->getActionPlugin(); 4221ab40613Stracker-user $toggles = $helper ? $helper->getRegisteredToggles() : []; 4231ab40613Stracker-user 4241ab40613Stracker-user if (empty($toggles) || $action === null) { 4251ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('notoggles')) . '</p>'; 4261ab40613Stracker-user $html .= '<p><a href="' . $this->pageURL() . '">' 4271ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a></p>'; 4281ab40613Stracker-user return $html . '</div>'; 4291ab40613Stracker-user } 4301ab40613Stracker-user 4311ab40613Stracker-user $formAction = wl($ID, ['do' => 'admin', 'page' => 'usersettings'], false, '&'); 4321ab40613Stracker-user $html .= '<form method="post" action="' . $formAction . '" class="us-form">'; 4331ab40613Stracker-user $html .= formSecurityToken(false); 4341ab40613Stracker-user $html .= '<input type="hidden" name="edituser" value="' . hsc($user) . '" />'; 4351ab40613Stracker-user $html .= '<input type="hidden" name="usersettings_adminsave" value="1" />'; 4361ab40613Stracker-user 4371ab40613Stracker-user foreach ($toggles as $key => $def) { 4381ab40613Stracker-user $html .= $action->renderToggleRow($def, $helper->getPreference($key, $user)); 4391ab40613Stracker-user } 4401ab40613Stracker-user 4411ab40613Stracker-user $html .= '<div class="us-actions">'; 4421ab40613Stracker-user $html .= '<button type="submit" class="button">' 4431ab40613Stracker-user . hsc($this->getLang('save')) . '</button> '; 4441ab40613Stracker-user $html .= '<a href="' . $this->pageURL() . '" class="us-back">' 4451ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a>'; 4461ab40613Stracker-user $html .= '</div>'; 4471ab40613Stracker-user $html .= '</form>'; 4481ab40613Stracker-user 4491ab40613Stracker-user return $html . '</div>'; 4501ab40613Stracker-user } 4511ab40613Stracker-user 4521ab40613Stracker-user // ---- helpers --------------------------------------------------------- 4531ab40613Stracker-user 4541ab40613Stracker-user /** 4551ab40613Stracker-user * Build a URL back to this admin page with the given extra parameters. 4561ab40613Stracker-user * 4571ab40613Stracker-user * @param array $params 4581ab40613Stracker-user * @return string HTML-attribute-safe URL 4591ab40613Stracker-user */ 4601ab40613Stracker-user protected function pageURL(array $params = []) 4611ab40613Stracker-user { 4621ab40613Stracker-user global $ID; 4631ab40613Stracker-user $base = ['do' => 'admin', 'page' => 'usersettings']; 4641ab40613Stracker-user return wl($ID, array_merge($base, $params), false, '&'); 4651ab40613Stracker-user } 4661ab40613Stracker-user} 467