1*1ab40613Stracker-user<?php 2*1ab40613Stracker-user 3*1ab40613Stracker-user/** 4*1ab40613Stracker-user * User Settings plugin — admin component. 5*1ab40613Stracker-user * 6*1ab40613Stracker-user * Provides an admin-only overview of every user's preferences as a flat, 7*1ab40613Stracker-user * sortable table: one row per (user x setting), with the columns 8*1ab40613Stracker-user * Display name | Setting | Value | Changed by | Changed at. 9*1ab40613Stracker-user * A row's value is the user's explicit choice, or the toggle's default 10*1ab40613Stracker-user * (marked as such) when they never set one. A filter narrows the table to a 11*1ab40613Stracker-user * single setting; the table never grows wider as more toggles are added. 12*1ab40613Stracker-user * 13*1ab40613Stracker-user * Clicking a display name opens a per-user edit form (Model A+: an admin may 14*1ab40613Stracker-user * change anyone's preferences). Such a change is stored with the admin as the 15*1ab40613Stracker-user * recorded actor, and the user can still change it back themselves later. 16*1ab40613Stracker-user */ 17*1ab40613Stracker-user 18*1ab40613Stracker-user// must be run within DokuWiki 19*1ab40613Stracker-userif (!defined('DOKU_INC')) die(); 20*1ab40613Stracker-user 21*1ab40613Stracker-userclass admin_plugin_usersettings extends DokuWiki_Admin_Plugin 22*1ab40613Stracker-user{ 23*1ab40613Stracker-user /** @var string[] sort key => row field used for that sort */ 24*1ab40613Stracker-user protected $sortFields = [ 25*1ab40613Stracker-user 'name' => 'display_name', 26*1ab40613Stracker-user 'setting' => 'setting_label', 27*1ab40613Stracker-user 'value' => 'value_display', 28*1ab40613Stracker-user 'changedby' => 'changed_by_display', 29*1ab40613Stracker-user 'changedat' => 'changed_at', 30*1ab40613Stracker-user ]; 31*1ab40613Stracker-user 32*1ab40613Stracker-user // --------------------------------------------------------------------- 33*1ab40613Stracker-user // Admin plugin metadata 34*1ab40613Stracker-user // --------------------------------------------------------------------- 35*1ab40613Stracker-user 36*1ab40613Stracker-user /** Only administrators may see other users' preferences. */ 37*1ab40613Stracker-user public function forAdminOnly() 38*1ab40613Stracker-user { 39*1ab40613Stracker-user return true; 40*1ab40613Stracker-user } 41*1ab40613Stracker-user 42*1ab40613Stracker-user /** Position in the admin menu. */ 43*1ab40613Stracker-user public function getMenuSort() 44*1ab40613Stracker-user { 45*1ab40613Stracker-user return 350; 46*1ab40613Stracker-user } 47*1ab40613Stracker-user 48*1ab40613Stracker-user /** Admin menu label — distinct from the user menu's "Preferences". */ 49*1ab40613Stracker-user public function getMenuText($language) 50*1ab40613Stracker-user { 51*1ab40613Stracker-user return $this->getLang('admin_menu'); 52*1ab40613Stracker-user } 53*1ab40613Stracker-user 54*1ab40613Stracker-user // --------------------------------------------------------------------- 55*1ab40613Stracker-user // Component access 56*1ab40613Stracker-user // --------------------------------------------------------------------- 57*1ab40613Stracker-user 58*1ab40613Stracker-user /** @return helper_plugin_usersettings|null */ 59*1ab40613Stracker-user protected function getHelper() 60*1ab40613Stracker-user { 61*1ab40613Stracker-user return plugin_load('helper', 'usersettings'); 62*1ab40613Stracker-user } 63*1ab40613Stracker-user 64*1ab40613Stracker-user /** @return action_plugin_usersettings|null */ 65*1ab40613Stracker-user protected function getActionPlugin() 66*1ab40613Stracker-user { 67*1ab40613Stracker-user return plugin_load('action', 'usersettings'); 68*1ab40613Stracker-user } 69*1ab40613Stracker-user 70*1ab40613Stracker-user // --------------------------------------------------------------------- 71*1ab40613Stracker-user // Request handling 72*1ab40613Stracker-user // --------------------------------------------------------------------- 73*1ab40613Stracker-user 74*1ab40613Stracker-user /** 75*1ab40613Stracker-user * Handle a submitted per-user edit form. 76*1ab40613Stracker-user * 77*1ab40613Stracker-user * Runs only for admins (DokuWiki's admin dispatcher enforces 78*1ab40613Stracker-user * forAdminOnly() before this is called). Uses Post/Redirect/Get. 79*1ab40613Stracker-user */ 80*1ab40613Stracker-user public function handle() 81*1ab40613Stracker-user { 82*1ab40613Stracker-user global $INPUT, $ID; 83*1ab40613Stracker-user 84*1ab40613Stracker-user if (!$INPUT->post->bool('usersettings_adminsave')) { 85*1ab40613Stracker-user return; 86*1ab40613Stracker-user } 87*1ab40613Stracker-user if (!checkSecurityToken()) { 88*1ab40613Stracker-user return; 89*1ab40613Stracker-user } 90*1ab40613Stracker-user 91*1ab40613Stracker-user $this->processAdminSave(); 92*1ab40613Stracker-user 93*1ab40613Stracker-user // Post/Redirect/Get back to the overview 94*1ab40613Stracker-user send_redirect(wl($ID, ['do' => 'admin', 'page' => 'usersettings'], true, '&')); 95*1ab40613Stracker-user } 96*1ab40613Stracker-user 97*1ab40613Stracker-user /** 98*1ab40613Stracker-user * Validate the target user and store the submitted preferences for them, 99*1ab40613Stracker-user * recording the acting admin as the actor. Kept redirect-free so it can 100*1ab40613Stracker-user * be tested directly. 101*1ab40613Stracker-user * 102*1ab40613Stracker-user * @return bool 103*1ab40613Stracker-user */ 104*1ab40613Stracker-user public function processAdminSave() 105*1ab40613Stracker-user { 106*1ab40613Stracker-user global $INPUT, $auth; 107*1ab40613Stracker-user 108*1ab40613Stracker-user $target = $INPUT->post->str('edituser'); 109*1ab40613Stracker-user $admin = $INPUT->server->str('REMOTE_USER'); 110*1ab40613Stracker-user 111*1ab40613Stracker-user $userData = ($auth !== null) ? $auth->getUserData($target) : false; 112*1ab40613Stracker-user if ($userData === false) { 113*1ab40613Stracker-user msg($this->getLang('badidentuser'), -1); 114*1ab40613Stracker-user return false; 115*1ab40613Stracker-user } 116*1ab40613Stracker-user 117*1ab40613Stracker-user $action = $this->getActionPlugin(); 118*1ab40613Stracker-user $ok = ($action !== null) && $action->saveSubmittedPreferences($target, $admin); 119*1ab40613Stracker-user 120*1ab40613Stracker-user $name = ($userData['name'] !== '') ? $userData['name'] : $target; 121*1ab40613Stracker-user msg( 122*1ab40613Stracker-user sprintf($this->getLang($ok ? 'adminsaved' : 'adminsavefail'), hsc($name)), 123*1ab40613Stracker-user $ok ? 1 : -1 124*1ab40613Stracker-user ); 125*1ab40613Stracker-user return $ok; 126*1ab40613Stracker-user } 127*1ab40613Stracker-user 128*1ab40613Stracker-user // --------------------------------------------------------------------- 129*1ab40613Stracker-user // Output 130*1ab40613Stracker-user // --------------------------------------------------------------------- 131*1ab40613Stracker-user 132*1ab40613Stracker-user /** 133*1ab40613Stracker-user * Render either the overview table or, when an edituser parameter is 134*1ab40613Stracker-user * present, the per-user edit form. 135*1ab40613Stracker-user */ 136*1ab40613Stracker-user public function html() 137*1ab40613Stracker-user { 138*1ab40613Stracker-user global $INPUT; 139*1ab40613Stracker-user 140*1ab40613Stracker-user $edituser = $INPUT->get->str('edituser'); 141*1ab40613Stracker-user if ($edituser !== '') { 142*1ab40613Stracker-user echo $this->renderEditForm($edituser); 143*1ab40613Stracker-user } else { 144*1ab40613Stracker-user echo $this->renderTable(); 145*1ab40613Stracker-user } 146*1ab40613Stracker-user } 147*1ab40613Stracker-user 148*1ab40613Stracker-user // ---- overview table -------------------------------------------------- 149*1ab40613Stracker-user 150*1ab40613Stracker-user /** 151*1ab40613Stracker-user * Build the rows of the overview: one per (user x toggle). 152*1ab40613Stracker-user * 153*1ab40613Stracker-user * @param array $users [username => userdata] as from $auth->retrieveUsers() 154*1ab40613Stracker-user * @param array $toggles registered toggle definitions 155*1ab40613Stracker-user * @return array list of row arrays 156*1ab40613Stracker-user */ 157*1ab40613Stracker-user public function buildRows(array $users, array $toggles) 158*1ab40613Stracker-user { 159*1ab40613Stracker-user $helper = $this->getHelper(); 160*1ab40613Stracker-user if ($helper === null) { 161*1ab40613Stracker-user return []; 162*1ab40613Stracker-user } 163*1ab40613Stracker-user 164*1ab40613Stracker-user $rows = []; 165*1ab40613Stracker-user foreach ($users as $username => $userData) { 166*1ab40613Stracker-user $displayName = (!empty($userData['name'])) ? $userData['name'] : $username; 167*1ab40613Stracker-user $stored = $helper->loadUserData($username); 168*1ab40613Stracker-user 169*1ab40613Stracker-user foreach ($toggles as $key => $def) { 170*1ab40613Stracker-user if (isset($stored[$key]) && array_key_exists('value', $stored[$key])) { 171*1ab40613Stracker-user $value = $stored[$key]['value']; 172*1ab40613Stracker-user $changedBy = $stored[$key]['changed_by'] ?? ''; 173*1ab40613Stracker-user $changedAt = (int) ($stored[$key]['changed_at'] ?? 0); 174*1ab40613Stracker-user $isDefault = false; 175*1ab40613Stracker-user } else { 176*1ab40613Stracker-user $value = $def['default']; 177*1ab40613Stracker-user $changedBy = ''; 178*1ab40613Stracker-user $changedAt = 0; 179*1ab40613Stracker-user $isDefault = true; 180*1ab40613Stracker-user } 181*1ab40613Stracker-user 182*1ab40613Stracker-user $rows[] = [ 183*1ab40613Stracker-user 'user' => $username, 184*1ab40613Stracker-user 'display_name' => $displayName, 185*1ab40613Stracker-user 'setting_key' => $key, 186*1ab40613Stracker-user 'setting_label' => $def['label'], 187*1ab40613Stracker-user 'value_display' => $this->displayValue($def, $value), 188*1ab40613Stracker-user 'is_default' => $isDefault, 189*1ab40613Stracker-user 'changed_by_display' => $isDefault ? '' : $this->resolveActor($changedBy, $users), 190*1ab40613Stracker-user 'changed_at' => $changedAt, 191*1ab40613Stracker-user ]; 192*1ab40613Stracker-user } 193*1ab40613Stracker-user } 194*1ab40613Stracker-user return $rows; 195*1ab40613Stracker-user } 196*1ab40613Stracker-user 197*1ab40613Stracker-user /** 198*1ab40613Stracker-user * Sort overview rows by the given column and direction. 199*1ab40613Stracker-user * 200*1ab40613Stracker-user * @param array $rows 201*1ab40613Stracker-user * @param string $sort one of the keys of $this->sortFields 202*1ab40613Stracker-user * @param string $dir 'asc' or 'desc' 203*1ab40613Stracker-user * @return array 204*1ab40613Stracker-user */ 205*1ab40613Stracker-user public function sortRows(array $rows, $sort, $dir) 206*1ab40613Stracker-user { 207*1ab40613Stracker-user $field = $this->sortFields[$sort] ?? 'display_name'; 208*1ab40613Stracker-user 209*1ab40613Stracker-user usort($rows, function ($a, $b) use ($field) { 210*1ab40613Stracker-user if ($field === 'changed_at') { 211*1ab40613Stracker-user return $a[$field] <=> $b[$field]; 212*1ab40613Stracker-user } 213*1ab40613Stracker-user return strcasecmp((string) $a[$field], (string) $b[$field]); 214*1ab40613Stracker-user }); 215*1ab40613Stracker-user 216*1ab40613Stracker-user if ($dir === 'desc') { 217*1ab40613Stracker-user $rows = array_reverse($rows); 218*1ab40613Stracker-user } 219*1ab40613Stracker-user return $rows; 220*1ab40613Stracker-user } 221*1ab40613Stracker-user 222*1ab40613Stracker-user /** 223*1ab40613Stracker-user * Human-readable value of a toggle: On/Off for a checkbox, the option 224*1ab40613Stracker-user * label for a select. 225*1ab40613Stracker-user * 226*1ab40613Stracker-user * @param array $def 227*1ab40613Stracker-user * @param mixed $value 228*1ab40613Stracker-user * @return string 229*1ab40613Stracker-user */ 230*1ab40613Stracker-user public function displayValue(array $def, $value) 231*1ab40613Stracker-user { 232*1ab40613Stracker-user if ($def['type'] === 'select') { 233*1ab40613Stracker-user if (isset($def['options'][$value])) { 234*1ab40613Stracker-user return (string) $def['options'][$value]; 235*1ab40613Stracker-user } 236*1ab40613Stracker-user return (string) $value; // stored value no longer a defined option 237*1ab40613Stracker-user } 238*1ab40613Stracker-user return $this->getLang(empty($value) ? 'val_off' : 'val_on'); 239*1ab40613Stracker-user } 240*1ab40613Stracker-user 241*1ab40613Stracker-user /** 242*1ab40613Stracker-user * Resolve an actor username to a display name, falling back to the raw 243*1ab40613Stracker-user * username when the actor is not (or no longer) a known user. 244*1ab40613Stracker-user * 245*1ab40613Stracker-user * @param string $actor 246*1ab40613Stracker-user * @param array $users [username => userdata] 247*1ab40613Stracker-user * @return string 248*1ab40613Stracker-user */ 249*1ab40613Stracker-user protected function resolveActor($actor, array $users) 250*1ab40613Stracker-user { 251*1ab40613Stracker-user if ($actor === '') { 252*1ab40613Stracker-user return ''; 253*1ab40613Stracker-user } 254*1ab40613Stracker-user if (isset($users[$actor]) && !empty($users[$actor]['name'])) { 255*1ab40613Stracker-user return $users[$actor]['name']; 256*1ab40613Stracker-user } 257*1ab40613Stracker-user return $actor; 258*1ab40613Stracker-user } 259*1ab40613Stracker-user 260*1ab40613Stracker-user /** 261*1ab40613Stracker-user * Render the overview table. 262*1ab40613Stracker-user * 263*1ab40613Stracker-user * @return string 264*1ab40613Stracker-user */ 265*1ab40613Stracker-user protected function renderTable() 266*1ab40613Stracker-user { 267*1ab40613Stracker-user global $INPUT, $auth; 268*1ab40613Stracker-user 269*1ab40613Stracker-user $helper = $this->getHelper(); 270*1ab40613Stracker-user $toggles = $helper ? $helper->getRegisteredToggles() : []; 271*1ab40613Stracker-user 272*1ab40613Stracker-user $html = '<div class="plugin_usersettings_admin">'; 273*1ab40613Stracker-user $html .= '<h1>' . hsc($this->getLang('admin_heading')) . '</h1>'; 274*1ab40613Stracker-user 275*1ab40613Stracker-user if (empty($toggles)) { 276*1ab40613Stracker-user return $html . '<p>' . hsc($this->getLang('notoggles')) . '</p></div>'; 277*1ab40613Stracker-user } 278*1ab40613Stracker-user 279*1ab40613Stracker-user $users = ($auth !== null) ? $auth->retrieveUsers(0, 0) : []; 280*1ab40613Stracker-user if (empty($users)) { 281*1ab40613Stracker-user return $html . '<p>' . hsc($this->getLang('nousers')) . '</p></div>'; 282*1ab40613Stracker-user } 283*1ab40613Stracker-user 284*1ab40613Stracker-user // request parameters (sort links and the filter form are GET) 285*1ab40613Stracker-user $sort = $INPUT->get->str('sort', 'name'); 286*1ab40613Stracker-user $dir = ($INPUT->get->str('dir') === 'desc') ? 'desc' : 'asc'; 287*1ab40613Stracker-user $filter = $INPUT->get->str('filter'); 288*1ab40613Stracker-user if (!isset($this->sortFields[$sort])) { 289*1ab40613Stracker-user $sort = 'name'; 290*1ab40613Stracker-user } 291*1ab40613Stracker-user if ($filter !== '' && !isset($toggles[$filter])) { 292*1ab40613Stracker-user $filter = ''; 293*1ab40613Stracker-user } 294*1ab40613Stracker-user 295*1ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('admin_intro')) . '</p>'; 296*1ab40613Stracker-user $html .= $this->renderFilter($toggles, $sort, $dir, $filter); 297*1ab40613Stracker-user 298*1ab40613Stracker-user // rows 299*1ab40613Stracker-user $rows = $this->buildRows($users, $toggles); 300*1ab40613Stracker-user if ($filter !== '') { 301*1ab40613Stracker-user $rows = array_values(array_filter($rows, function ($r) use ($filter) { 302*1ab40613Stracker-user return $r['setting_key'] === $filter; 303*1ab40613Stracker-user })); 304*1ab40613Stracker-user } 305*1ab40613Stracker-user $rows = $this->sortRows($rows, $sort, $dir); 306*1ab40613Stracker-user 307*1ab40613Stracker-user // table 308*1ab40613Stracker-user $html .= '<table class="inline plugin_usersettings_table">'; 309*1ab40613Stracker-user $html .= '<thead><tr>'; 310*1ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_name'), 'name', $sort, $dir, $filter); 311*1ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_setting'), 'setting', $sort, $dir, $filter); 312*1ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_value'), 'value', $sort, $dir, $filter); 313*1ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_changedby'), 'changedby', $sort, $dir, $filter); 314*1ab40613Stracker-user $html .= $this->sortHeader($this->getLang('th_changedat'), 'changedat', $sort, $dir, $filter); 315*1ab40613Stracker-user $html .= '</tr></thead><tbody>'; 316*1ab40613Stracker-user 317*1ab40613Stracker-user foreach ($rows as $row) { 318*1ab40613Stracker-user $rowClass = $row['is_default'] ? ' class="us-default-row"' : ''; 319*1ab40613Stracker-user $editUrl = $this->pageURL(['edituser' => $row['user']]); 320*1ab40613Stracker-user 321*1ab40613Stracker-user $html .= '<tr' . $rowClass . '>'; 322*1ab40613Stracker-user $html .= '<td><a href="' . $editUrl . '">' . hsc($row['display_name']) . '</a></td>'; 323*1ab40613Stracker-user $html .= '<td>' . hsc($row['setting_label']) . '</td>'; 324*1ab40613Stracker-user $html .= '<td>' . hsc($row['value_display']) . '</td>'; 325*1ab40613Stracker-user $html .= '<td>' . ($row['is_default'] 326*1ab40613Stracker-user ? '<span class="us-default-mark">' . hsc($this->getLang('bydefault')) . '</span>' 327*1ab40613Stracker-user : hsc($row['changed_by_display'])) . '</td>'; 328*1ab40613Stracker-user $html .= '<td>' . ($row['changed_at'] > 0 ? hsc(dformat($row['changed_at'])) : '—') . '</td>'; 329*1ab40613Stracker-user $html .= '</tr>'; 330*1ab40613Stracker-user } 331*1ab40613Stracker-user 332*1ab40613Stracker-user $html .= '</tbody></table>'; 333*1ab40613Stracker-user return $html . '</div>'; 334*1ab40613Stracker-user } 335*1ab40613Stracker-user 336*1ab40613Stracker-user /** 337*1ab40613Stracker-user * Render the setting filter (a small GET form). 338*1ab40613Stracker-user * 339*1ab40613Stracker-user * @param array $toggles 340*1ab40613Stracker-user * @param string $sort 341*1ab40613Stracker-user * @param string $dir 342*1ab40613Stracker-user * @param string $filter currently selected setting key 343*1ab40613Stracker-user * @return string 344*1ab40613Stracker-user */ 345*1ab40613Stracker-user protected function renderFilter(array $toggles, $sort, $dir, $filter) 346*1ab40613Stracker-user { 347*1ab40613Stracker-user global $ID; 348*1ab40613Stracker-user 349*1ab40613Stracker-user // GET forms drop the action URL's query string, so every parameter 350*1ab40613Stracker-user // travels as an explicit field — this also survives URL rewriting. 351*1ab40613Stracker-user $html = '<form class="us-filter" method="get" action="' . DOKU_BASE . DOKU_SCRIPT . '">'; 352*1ab40613Stracker-user $html .= '<input type="hidden" name="id" value="' . hsc($ID) . '" />'; 353*1ab40613Stracker-user $html .= '<input type="hidden" name="do" value="admin" />'; 354*1ab40613Stracker-user $html .= '<input type="hidden" name="page" value="usersettings" />'; 355*1ab40613Stracker-user $html .= '<input type="hidden" name="sort" value="' . hsc($sort) . '" />'; 356*1ab40613Stracker-user $html .= '<input type="hidden" name="dir" value="' . hsc($dir) . '" />'; 357*1ab40613Stracker-user 358*1ab40613Stracker-user $html .= '<label>' . hsc($this->getLang('filter_label')) . ' '; 359*1ab40613Stracker-user $html .= '<select name="filter">'; 360*1ab40613Stracker-user $html .= '<option value="">' . hsc($this->getLang('filter_all')) . '</option>'; 361*1ab40613Stracker-user foreach ($toggles as $key => $def) { 362*1ab40613Stracker-user $selected = ($filter === $key) ? ' selected="selected"' : ''; 363*1ab40613Stracker-user $html .= '<option value="' . hsc($key) . '"' . $selected . '>' 364*1ab40613Stracker-user . hsc($def['label']) . '</option>'; 365*1ab40613Stracker-user } 366*1ab40613Stracker-user $html .= '</select></label> '; 367*1ab40613Stracker-user $html .= '<button type="submit">' . hsc($this->getLang('filter_apply')) . '</button>'; 368*1ab40613Stracker-user return $html . '</form>'; 369*1ab40613Stracker-user } 370*1ab40613Stracker-user 371*1ab40613Stracker-user /** 372*1ab40613Stracker-user * Render one sortable column header. 373*1ab40613Stracker-user * 374*1ab40613Stracker-user * @param string $label 375*1ab40613Stracker-user * @param string $col sort key for this column 376*1ab40613Stracker-user * @param string $sort currently active sort key 377*1ab40613Stracker-user * @param string $dir currently active direction 378*1ab40613Stracker-user * @param string $filter currently active filter (preserved in the link) 379*1ab40613Stracker-user * @return string 380*1ab40613Stracker-user */ 381*1ab40613Stracker-user protected function sortHeader($label, $col, $sort, $dir, $filter) 382*1ab40613Stracker-user { 383*1ab40613Stracker-user // clicking the active column flips direction; others start ascending 384*1ab40613Stracker-user $newDir = ($sort === $col && $dir === 'asc') ? 'desc' : 'asc'; 385*1ab40613Stracker-user $arrow = ''; 386*1ab40613Stracker-user if ($sort === $col) { 387*1ab40613Stracker-user $arrow = ($dir === 'asc') ? " \u{25B2}" : " \u{25BC}"; 388*1ab40613Stracker-user } 389*1ab40613Stracker-user 390*1ab40613Stracker-user $url = $this->pageURL(['sort' => $col, 'dir' => $newDir, 'filter' => $filter]); 391*1ab40613Stracker-user return '<th><a href="' . $url . '">' . hsc($label) . $arrow . '</a></th>'; 392*1ab40613Stracker-user } 393*1ab40613Stracker-user 394*1ab40613Stracker-user // ---- per-user edit form --------------------------------------------- 395*1ab40613Stracker-user 396*1ab40613Stracker-user /** 397*1ab40613Stracker-user * Render the edit form for one user's preferences. 398*1ab40613Stracker-user * 399*1ab40613Stracker-user * @param string $user 400*1ab40613Stracker-user * @return string 401*1ab40613Stracker-user */ 402*1ab40613Stracker-user protected function renderEditForm($user) 403*1ab40613Stracker-user { 404*1ab40613Stracker-user global $auth, $ID; 405*1ab40613Stracker-user 406*1ab40613Stracker-user $html = '<div class="plugin_usersettings_admin">'; 407*1ab40613Stracker-user 408*1ab40613Stracker-user $userData = ($auth !== null) ? $auth->getUserData($user) : false; 409*1ab40613Stracker-user if ($userData === false) { 410*1ab40613Stracker-user $html .= '<h1>' . hsc($this->getLang('admin_heading')) . '</h1>'; 411*1ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('badidentuser')) . '</p>'; 412*1ab40613Stracker-user $html .= '<p><a href="' . $this->pageURL() . '">' 413*1ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a></p>'; 414*1ab40613Stracker-user return $html . '</div>'; 415*1ab40613Stracker-user } 416*1ab40613Stracker-user 417*1ab40613Stracker-user $displayName = ($userData['name'] !== '') ? $userData['name'] : $user; 418*1ab40613Stracker-user $html .= '<h1>' . hsc(sprintf($this->getLang('edit_heading'), $displayName)) . '</h1>'; 419*1ab40613Stracker-user 420*1ab40613Stracker-user $helper = $this->getHelper(); 421*1ab40613Stracker-user $action = $this->getActionPlugin(); 422*1ab40613Stracker-user $toggles = $helper ? $helper->getRegisteredToggles() : []; 423*1ab40613Stracker-user 424*1ab40613Stracker-user if (empty($toggles) || $action === null) { 425*1ab40613Stracker-user $html .= '<p>' . hsc($this->getLang('notoggles')) . '</p>'; 426*1ab40613Stracker-user $html .= '<p><a href="' . $this->pageURL() . '">' 427*1ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a></p>'; 428*1ab40613Stracker-user return $html . '</div>'; 429*1ab40613Stracker-user } 430*1ab40613Stracker-user 431*1ab40613Stracker-user $formAction = wl($ID, ['do' => 'admin', 'page' => 'usersettings'], false, '&'); 432*1ab40613Stracker-user $html .= '<form method="post" action="' . $formAction . '" class="us-form">'; 433*1ab40613Stracker-user $html .= formSecurityToken(false); 434*1ab40613Stracker-user $html .= '<input type="hidden" name="edituser" value="' . hsc($user) . '" />'; 435*1ab40613Stracker-user $html .= '<input type="hidden" name="usersettings_adminsave" value="1" />'; 436*1ab40613Stracker-user 437*1ab40613Stracker-user foreach ($toggles as $key => $def) { 438*1ab40613Stracker-user $html .= $action->renderToggleRow($def, $helper->getPreference($key, $user)); 439*1ab40613Stracker-user } 440*1ab40613Stracker-user 441*1ab40613Stracker-user $html .= '<div class="us-actions">'; 442*1ab40613Stracker-user $html .= '<button type="submit" class="button">' 443*1ab40613Stracker-user . hsc($this->getLang('save')) . '</button> '; 444*1ab40613Stracker-user $html .= '<a href="' . $this->pageURL() . '" class="us-back">' 445*1ab40613Stracker-user . hsc($this->getLang('edit_back')) . '</a>'; 446*1ab40613Stracker-user $html .= '</div>'; 447*1ab40613Stracker-user $html .= '</form>'; 448*1ab40613Stracker-user 449*1ab40613Stracker-user return $html . '</div>'; 450*1ab40613Stracker-user } 451*1ab40613Stracker-user 452*1ab40613Stracker-user // ---- helpers --------------------------------------------------------- 453*1ab40613Stracker-user 454*1ab40613Stracker-user /** 455*1ab40613Stracker-user * Build a URL back to this admin page with the given extra parameters. 456*1ab40613Stracker-user * 457*1ab40613Stracker-user * @param array $params 458*1ab40613Stracker-user * @return string HTML-attribute-safe URL 459*1ab40613Stracker-user */ 460*1ab40613Stracker-user protected function pageURL(array $params = []) 461*1ab40613Stracker-user { 462*1ab40613Stracker-user global $ID; 463*1ab40613Stracker-user $base = ['do' => 'admin', 'page' => 'usersettings']; 464*1ab40613Stracker-user return wl($ID, array_merge($base, $params), false, '&'); 465*1ab40613Stracker-user } 466*1ab40613Stracker-user} 467