]>
Commit | Line | Data |
---|---|---|
66665fba | 1 | <?php |
369dbc19 | 2 | class Pref_Users extends Handler_Protected { |
17f9d200 JK |
3 | function before($method) { |
4 | if (parent::before($method)) { | |
66665fba AD |
5 | if ($_SESSION["access_level"] < 10) { |
6 | print __("Your access level is insufficient to open this tab."); | |
7 | return false; | |
8 | } | |
9 | return true; | |
10 | } | |
11 | return false; | |
12 | } | |
13 | ||
8484ce22 | 14 | function csrf_ignore($method) { |
d9afd9b2 | 15 | $csrf_ignored = array("index", "edit", "userdetails"); |
8484ce22 AD |
16 | |
17 | return array_search($method, $csrf_ignored) !== false; | |
18 | } | |
19 | ||
66665fba AD |
20 | function edit() { |
21 | global $access_level_names; | |
22 | ||
05e81655 AD |
23 | print "<form id=\"user_edit_form\" onsubmit='return false' dojoType=\"dijit.form.Form\">"; |
24 | ||
bf9cc9ad AD |
25 | print '<div dojoType="dijit.layout.TabContainer" style="height : 400px"> |
26 | <div dojoType="dijit.layout.ContentPane" title="'.__('Edit user').'">'; | |
27 | ||
05e81655 | 28 | //print "<form id=\"user_edit_form\" onsubmit='return false' dojoType=\"dijit.form.Form\">"; |
66665fba | 29 | |
e6532439 | 30 | $id = (int) clean($_REQUEST["id"]); |
bf9cc9ad | 31 | |
328118d1 AD |
32 | print_hidden("id", "$id"); |
33 | print_hidden("op", "pref-users"); | |
34 | print_hidden("method", "editSave"); | |
66665fba | 35 | |
c2418a55 AD |
36 | $sth = $this->pdo->prepare("SELECT * FROM ttrss_users WHERE id = ?"); |
37 | $sth->execute([$id]); | |
66665fba | 38 | |
c2418a55 | 39 | if ($row = $sth->fetch()) { |
66665fba | 40 | |
c2418a55 AD |
41 | $login = $row["login"]; |
42 | $access_level = $row["access_level"]; | |
43 | $email = $row["email"]; | |
66665fba | 44 | |
c2418a55 | 45 | $sel_disabled = ($id == $_SESSION["uid"] || $login == "admin") ? "disabled" : ""; |
66665fba | 46 | |
c2418a55 AD |
47 | print "<div class=\"dlgSec\">".__("User")."</div>"; |
48 | print "<div class=\"dlgSecCont\">"; | |
66665fba | 49 | |
c2418a55 AD |
50 | if ($sel_disabled) { |
51 | print_hidden("login", "$login"); | |
52 | } | |
222a61c2 | 53 | |
c2418a55 AD |
54 | print "<input size=\"30\" style=\"font-size : 16px\" |
55 | dojoType=\"dijit.form.ValidationTextBox\" required=\"1\" | |
56 | $sel_disabled | |
57 | name=\"login\" value=\"$login\">"; | |
66665fba | 58 | |
c2418a55 | 59 | print "</div>"; |
66665fba | 60 | |
c2418a55 AD |
61 | print "<div class=\"dlgSec\">".__("Authentication")."</div>"; |
62 | print "<div class=\"dlgSecCont\">"; | |
66665fba | 63 | |
c2418a55 AD |
64 | print __('Access level: ') . " "; |
65 | ||
66 | if (!$sel_disabled) { | |
67 | print_select_hash("access_level", $access_level, $access_level_names, | |
68 | "dojoType=\"dijit.form.Select\" $sel_disabled"); | |
69 | } else { | |
70 | print_select_hash("", $access_level, $access_level_names, | |
71 | "dojoType=\"dijit.form.Select\" $sel_disabled"); | |
72 | print_hidden("access_level", "$access_level"); | |
73 | } | |
66665fba | 74 | |
c2418a55 | 75 | print "<hr/>"; |
66665fba | 76 | |
c2418a55 | 77 | print "<input dojoType=\"dijit.form.TextBox\" type=\"password\" size=\"20\" placeholder=\"Change password\" |
66665fba AD |
78 | name=\"password\">"; |
79 | ||
c2418a55 | 80 | print "</div>"; |
66665fba | 81 | |
c2418a55 AD |
82 | print "<div class=\"dlgSec\">".__("Options")."</div>"; |
83 | print "<div class=\"dlgSecCont\">"; | |
66665fba | 84 | |
c2418a55 | 85 | print "<input dojoType=\"dijit.form.TextBox\" size=\"30\" name=\"email\" placeholder=\"E-mail\" |
66665fba AD |
86 | value=\"$email\">"; |
87 | ||
c2418a55 | 88 | print "</div>"; |
66665fba | 89 | |
c2418a55 | 90 | print "</table>"; |
66665fba | 91 | |
c2418a55 | 92 | } |
66665fba | 93 | |
bf9cc9ad AD |
94 | print '</div>'; #tab |
95 | print "<div href=\"backend.php?op=pref-users&method=userdetails&id=$id\" | |
96 | dojoType=\"dijit.layout.ContentPane\" title=\"".__('User details')."\">"; | |
97 | ||
98 | print '</div>'; | |
99 | print '</div>'; | |
100 | ||
66665fba | 101 | print "<div class=\"dlgButtons\"> |
05e81655 | 102 | <button dojoType=\"dijit.form.Button\" class=\"btn-primary\" type=\"submit\" onclick=\"dijit.byId('userEditDlg').execute()\">". |
bf9cc9ad | 103 | __('Save')."</button> |
222a61c2 | 104 | <button dojoType=\"dijit.form.Button\" onclick=\"dijit.byId('userEditDlg').hide()\">". |
bf9cc9ad | 105 | __('Cancel')."</button></div>"; |
66665fba | 106 | |
05e81655 AD |
107 | print "</form>"; |
108 | ||
66665fba AD |
109 | return; |
110 | } | |
111 | ||
bf9cc9ad | 112 | function userdetails() { |
e6532439 | 113 | $id = (int) clean($_REQUEST["id"]); |
bf9cc9ad | 114 | |
c2418a55 | 115 | $sth = $this->pdo->prepare("SELECT login, |
bf9cc9ad AD |
116 | ".SUBSTRING_FOR_DATE."(last_login,1,16) AS last_login, |
117 | access_level, | |
118 | (SELECT COUNT(int_id) FROM ttrss_user_entries | |
119 | WHERE owner_uid = id) AS stored_articles, | |
120 | ".SUBSTRING_FOR_DATE."(created,1,16) AS created | |
121 | FROM ttrss_users | |
c2418a55 AD |
122 | WHERE id = ?"); |
123 | $sth->execute([$id]); | |
bf9cc9ad | 124 | |
c2418a55 AD |
125 | if ($row = $sth->fetch()) { |
126 | print "<table width='100%'>"; | |
bf9cc9ad | 127 | |
c2418a55 AD |
128 | $last_login = make_local_datetime( |
129 | $row["last_login"], true); | |
bf9cc9ad | 130 | |
c2418a55 AD |
131 | $created = make_local_datetime( |
132 | $row["created"], true); | |
bf9cc9ad | 133 | |
c2418a55 | 134 | $stored_articles = $row["stored_articles"]; |
bf9cc9ad | 135 | |
c2418a55 AD |
136 | print "<tr><td>".__('Registered')."</td><td>$created</td></tr>"; |
137 | print "<tr><td>".__('Last logged in')."</td><td>$last_login</td></tr>"; | |
bf9cc9ad | 138 | |
c2418a55 AD |
139 | $sth = $this->pdo->prepare("SELECT COUNT(id) as num_feeds FROM ttrss_feeds |
140 | WHERE owner_uid = ?"); | |
141 | $sth->execute([$id]); | |
142 | $row = $sth->fetch(); | |
143 | $num_feeds = $row["num_feeds"]; | |
bf9cc9ad | 144 | |
c2418a55 AD |
145 | print "<tr><td>".__('Subscribed feeds count')."</td><td>$num_feeds</td></tr>"; |
146 | print "<tr><td>".__('Stored articles')."</td><td>$stored_articles</td></tr>"; | |
bf9cc9ad | 147 | |
c2418a55 | 148 | print "</table>"; |
bf9cc9ad | 149 | |
c2418a55 | 150 | print "<h1>".__('Subscribed feeds')."</h1>"; |
bf9cc9ad | 151 | |
c2418a55 AD |
152 | $sth = $this->pdo->prepare("SELECT id,title,site_url FROM ttrss_feeds |
153 | WHERE owner_uid = ? ORDER BY title"); | |
154 | $sth->execute([$id]); | |
bf9cc9ad | 155 | |
c2418a55 | 156 | print "<ul class=\"userFeedList\">"; |
bf9cc9ad | 157 | |
c2418a55 | 158 | while ($line = $sth->fetch()) { |
bf9cc9ad | 159 | |
c2418a55 | 160 | $icon_file = ICONS_URL."/".$line["id"].".ico"; |
bf9cc9ad | 161 | |
c2418a55 AD |
162 | if (file_exists($icon_file) && filesize($icon_file) > 0) { |
163 | $feed_icon = "<img class=\"tinyFeedIcon\" src=\"$icon_file\">"; | |
164 | } else { | |
165 | $feed_icon = "<img class=\"tinyFeedIcon\" src=\"images/blank_icon.gif\">"; | |
166 | } | |
bf9cc9ad | 167 | |
c2418a55 | 168 | print "<li>$feed_icon <a href=\"".$line["site_url"]."\">".$line["title"]."</a></li>"; |
bf9cc9ad | 169 | |
bf9cc9ad AD |
170 | } |
171 | ||
c2418a55 | 172 | print "</ul>"; |
3a029230 AD |
173 | |
174 | ||
c2418a55 AD |
175 | } else { |
176 | print "<h1>".__('User not found')."</h1>"; | |
bf9cc9ad | 177 | } |
3a029230 | 178 | |
bf9cc9ad AD |
179 | } |
180 | ||
66665fba | 181 | function editSave() { |
e6532439 AD |
182 | $login = trim(clean($_REQUEST["login"])); |
183 | $uid = clean($_REQUEST["id"]); | |
184 | $access_level = (int) clean($_REQUEST["access_level"]); | |
185 | $email = trim(clean($_REQUEST["email"])); | |
186 | $password = clean($_REQUEST["password"]); | |
66665fba AD |
187 | |
188 | if ($password) { | |
8db5d8ea | 189 | $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); |
098df83b | 190 | $pwd_hash = encrypt_password($password, $salt, true); |
3a029230 | 191 | $pass_query_part = "pwd_hash = ".$this->pdo->quote($pwd_hash).", |
c2418a55 | 192 | salt = ".$this->pdo->quote($salt).","; |
66665fba AD |
193 | } else { |
194 | $pass_query_part = ""; | |
195 | } | |
196 | ||
c2418a55 AD |
197 | $sth = $this->pdo->prepare("UPDATE ttrss_users SET $pass_query_part login = ?, |
198 | access_level = ?, email = ?, otp_enabled = false WHERE id = ?"); | |
199 | $sth->execute([$login, $access_level, $email, $uid]); | |
66665fba AD |
200 | |
201 | } | |
202 | ||
203 | function remove() { | |
e6532439 | 204 | $ids = explode(",", clean($_REQUEST["ids"])); |
66665fba AD |
205 | |
206 | foreach ($ids as $id) { | |
207 | if ($id != $_SESSION["uid"] && $id != 1) { | |
c2418a55 AD |
208 | $sth = $this->pdo->prepare("DELETE FROM ttrss_tags WHERE owner_uid = ?"); |
209 | $sth->execute([$id]); | |
210 | ||
211 | $sth = $this->pdo->prepare("DELETE FROM ttrss_feeds WHERE owner_uid = ?"); | |
212 | $sth->execute([$id]); | |
213 | ||
214 | $sth = $this->pdo->prepare("DELETE FROM ttrss_users WHERE id = ?"); | |
215 | $sth->execute([$id]); | |
66665fba AD |
216 | } |
217 | } | |
218 | } | |
219 | ||
220 | function add() { | |
221 | ||
e6532439 | 222 | $login = trim(clean($_REQUEST["login"])); |
66665fba | 223 | $tmp_user_pwd = make_password(8); |
8db5d8ea | 224 | $salt = substr(bin2hex(get_random_bytes(125)), 0, 250); |
098df83b | 225 | $pwd_hash = encrypt_password($tmp_user_pwd, $salt, true); |
66665fba | 226 | |
c2418a55 AD |
227 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE |
228 | login = ?"); | |
229 | $sth->execute([$login]); | |
66665fba | 230 | |
c2418a55 | 231 | if (!$sth->fetch()) { |
66665fba | 232 | |
c2418a55 | 233 | $sth = $this->pdo->prepare("INSERT INTO ttrss_users |
098df83b | 234 | (login,pwd_hash,access_level,last_login,created, salt) |
c2418a55 AD |
235 | VALUES (?, ?, 0, null, NOW(), ?)"); |
236 | $sth->execute([$login, $pwd_hash, $salt]); | |
66665fba | 237 | |
c2418a55 AD |
238 | $sth = $this->pdo->prepare("SELECT id FROM ttrss_users WHERE |
239 | login = ? AND pwd_hash = ?"); | |
240 | $sth->execute([$login, $pwd_hash]); | |
66665fba | 241 | |
c2418a55 | 242 | if ($row = $sth->fetch()) { |
66665fba | 243 | |
c2418a55 | 244 | $new_uid = $row['id']; |
66665fba AD |
245 | |
246 | print format_notice(T_sprintf("Added user <b>%s</b> with password <b>%s</b>", | |
247 | $login, $tmp_user_pwd)); | |
248 | ||
a42c55f0 | 249 | initialize_user($new_uid); |
66665fba AD |
250 | |
251 | } else { | |
252 | ||
253 | print format_warning(T_sprintf("Could not create user <b>%s</b>", $login)); | |
254 | ||
255 | } | |
256 | } else { | |
257 | print format_warning(T_sprintf("User <b>%s</b> already exists.", $login)); | |
258 | } | |
259 | } | |
260 | ||
233b74ad | 261 | static function resetUserPassword($uid, $show_password) { |
66665fba | 262 | |
c2418a55 | 263 | $pdo = Db::pdo(); |
66665fba | 264 | |
c2418a55 AD |
265 | $sth = $pdo->prepare("SELECT login, email |
266 | FROM ttrss_users WHERE id = ?"); | |
267 | $sth->execute([$uid]); | |
3a029230 | 268 | |
c2418a55 | 269 | if ($row = $sth->fetch()) { |
098df83b | 270 | |
c2418a55 AD |
271 | $login = $row["login"]; |
272 | $email = $row["email"]; | |
66665fba | 273 | |
c2418a55 AD |
274 | $new_salt = substr(bin2hex(get_random_bytes(125)), 0, 250); |
275 | $tmp_user_pwd = make_password(8); | |
098df83b | 276 | |
c2418a55 | 277 | $pwd_hash = encrypt_password($tmp_user_pwd, $new_salt, true); |
66665fba | 278 | |
3a029230 | 279 | $sth = $pdo->prepare("UPDATE ttrss_users |
c2418a55 AD |
280 | SET pwd_hash = ?, salt = ?, otp_enabled = false |
281 | WHERE id = ?"); | |
282 | $sth->execute([$pwd_hash, $new_salt, $uid]); | |
66665fba | 283 | |
c2418a55 AD |
284 | if ($show_password) { |
285 | print T_sprintf("Changed password of user <b>%s</b> to <b>%s</b>", $login, $tmp_user_pwd); | |
286 | } else { | |
287 | print_notice(T_sprintf("Sending new password of user <b>%s</b> to <b>%s</b>", $login, $email)); | |
288 | } | |
289 | ||
c2418a55 AD |
290 | if ($email) { |
291 | require_once "lib/MiniTemplator.class.php"; | |
66665fba | 292 | |
c2418a55 | 293 | $tpl = new MiniTemplator; |
66665fba | 294 | |
c2418a55 | 295 | $tpl->readTemplateFromFile("templates/resetpass_template.txt"); |
66665fba | 296 | |
c2418a55 AD |
297 | $tpl->setVariable('LOGIN', $login); |
298 | $tpl->setVariable('NEWPASS', $tmp_user_pwd); | |
66665fba | 299 | |
c2418a55 | 300 | $tpl->addBlock('message'); |
66665fba | 301 | |
c2418a55 | 302 | $message = ""; |
66665fba | 303 | |
c2418a55 | 304 | $tpl->generateOutputToString($message); |
66665fba | 305 | |
57932e18 | 306 | $mailer = new Mailer(); |
66665fba | 307 | |
55bf4bc1 AD |
308 | $rc = $mailer->mail(["to_name" => $login, |
309 | "to_address" => $email, | |
57932e18 AD |
310 | "subject" => __("[tt-rss] Password change notification"), |
311 | "message" => $message]); | |
66665fba | 312 | |
57932e18 | 313 | if (!$rc) print_error($mailer->error()); |
c2418a55 | 314 | } |
3a029230 | 315 | |
66665fba | 316 | } |
f43e9e97 | 317 | } |
66665fba | 318 | |
f43e9e97 | 319 | function resetPass() { |
e6532439 | 320 | $uid = clean($_REQUEST["id"]); |
a42c55f0 | 321 | Pref_Users::resetUserPassword($uid, true); |
66665fba AD |
322 | } |
323 | ||
324 | function index() { | |
325 | ||
326 | global $access_level_names; | |
327 | ||
328 | print "<div id=\"pref-user-wrap\" dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">"; | |
329 | print "<div id=\"pref-user-header\" dojoType=\"dijit.layout.ContentPane\" region=\"top\">"; | |
330 | ||
331 | print "<div id=\"pref-user-toolbar\" dojoType=\"dijit.Toolbar\">"; | |
332 | ||
e6532439 | 333 | $user_search = trim(clean($_REQUEST["search"])); |
66665fba AD |
334 | |
335 | if (array_key_exists("search", $_REQUEST)) { | |
336 | $_SESSION["prefs_user_search"] = $user_search; | |
337 | } else { | |
338 | $user_search = $_SESSION["prefs_user_search"]; | |
339 | } | |
340 | ||
341 | print "<div style='float : right; padding-right : 4px;'> | |
342 | <input dojoType=\"dijit.form.TextBox\" id=\"user_search\" size=\"20\" type=\"search\" | |
343 | value=\"$user_search\"> | |
808ef3d4 | 344 | <button dojoType=\"dijit.form.Button\" onclick=\"updateUsersList()\">". |
66665fba AD |
345 | __('Search')."</button> |
346 | </div>"; | |
347 | ||
e6532439 | 348 | $sort = clean($_REQUEST["sort"]); |
66665fba AD |
349 | |
350 | if (!$sort || $sort == "undefined") { | |
351 | $sort = "login"; | |
352 | } | |
353 | ||
354 | print "<div dojoType=\"dijit.form.DropDownButton\">". | |
355 | "<span>" . __('Select')."</span>"; | |
356 | print "<div dojoType=\"dijit.Menu\" style=\"display: none;\">"; | |
357 | print "<div onclick=\"selectTableRows('prefUserList', 'all')\" | |
358 | dojoType=\"dijit.MenuItem\">".__('All')."</div>"; | |
359 | print "<div onclick=\"selectTableRows('prefUserList', 'none')\" | |
360 | dojoType=\"dijit.MenuItem\">".__('None')."</div>"; | |
361 | print "</div></div>"; | |
362 | ||
808ef3d4 | 363 | print "<button dojoType=\"dijit.form.Button\" onclick=\"addUser()\">".__('Create user')."</button>"; |
66665fba AD |
364 | |
365 | print " | |
808ef3d4 | 366 | <button dojoType=\"dijit.form.Button\" onclick=\"editSelectedUser()\">". |
66665fba | 367 | __('Edit')."</button dojoType=\"dijit.form.Button\"> |
808ef3d4 | 368 | <button dojoType=\"dijit.form.Button\" onclick=\"removeSelectedUsers()\">". |
66665fba | 369 | __('Remove')."</button dojoType=\"dijit.form.Button\"> |
808ef3d4 | 370 | <button dojoType=\"dijit.form.Button\" onclick=\"resetSelectedUserPass()\">". |
66665fba AD |
371 | __('Reset password')."</button dojoType=\"dijit.form.Button\">"; |
372 | ||
610fe115 AD |
373 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, |
374 | "hook_prefs_tab_section", "prefUsersToolbar"); | |
375 | ||
66665fba AD |
376 | print "</div>"; #toolbar |
377 | print "</div>"; #pane | |
378 | print "<div id=\"pref-user-content\" dojoType=\"dijit.layout.ContentPane\" region=\"center\">"; | |
379 | ||
2cf93c04 AD |
380 | $sort = validate_field($sort, |
381 | ["login", "access_level", "created", "num_feeds", "created", "last_login"], "login"); | |
382 | ||
383 | if ($sort != "login") $sort = "$sort DESC"; | |
66665fba | 384 | |
c2418a55 | 385 | $sth = $this->pdo->prepare("SELECT |
1edff0d4 AD |
386 | tu.id, |
387 | login,access_level,email, | |
66665fba | 388 | ".SUBSTRING_FOR_DATE."(last_login,1,16) as last_login, |
1edff0d4 | 389 | ".SUBSTRING_FOR_DATE."(created,1,16) as created, |
f232aa5a | 390 | (SELECT COUNT(id) FROM ttrss_feeds WHERE owner_uid = tu.id) AS num_feeds |
66665fba | 391 | FROM |
1edff0d4 | 392 | ttrss_users tu |
66665fba | 393 | WHERE |
c2418a55 | 394 | (:search = '' OR login LIKE :search) AND tu.id > 0 |
2cf93c04 AD |
395 | ORDER BY $sort"); |
396 | $sth->execute([":search" => $user_search ? "%$user_search%" : ""]); | |
66665fba AD |
397 | |
398 | print "<p><table width=\"100%\" cellspacing=\"0\" | |
399 | class=\"prefUserList\" id=\"prefUserList\">"; | |
400 | ||
401 | print "<tr class=\"title\"> | |
402 | <td align='center' width=\"5%\"> </td> | |
1edff0d4 AD |
403 | <td width='20%'><a href=\"#\" onclick=\"updateUsersList('login')\">".__('Login')."</a></td> |
404 | <td width='20%'><a href=\"#\" onclick=\"updateUsersList('access_level')\">".__('Access Level')."</a></td> | |
405 | <td width='10%'><a href=\"#\" onclick=\"updateUsersList('num_feeds')\">".__('Subscribed feeds')."</a></td> | |
66665fba AD |
406 | <td width='20%'><a href=\"#\" onclick=\"updateUsersList('created')\">".__('Registered')."</a></td> |
407 | <td width='20%'><a href=\"#\" onclick=\"updateUsersList('last_login')\">".__('Last login')."</a></td></tr>"; | |
408 | ||
409 | $lnum = 0; | |
410 | ||
c2418a55 | 411 | while ($line = $sth->fetch()) { |
66665fba | 412 | |
66665fba AD |
413 | $uid = $line["id"]; |
414 | ||
84391d69 | 415 | print "<tr id=\"UMRR-$uid\">"; |
66665fba AD |
416 | |
417 | $line["login"] = htmlspecialchars($line["login"]); | |
418 | ||
a42c55f0 AD |
419 | $line["created"] = make_local_datetime($line["created"], false); |
420 | $line["last_login"] = make_local_datetime($line["last_login"], false); | |
66665fba | 421 | |
84391d69 AD |
422 | print "<td align='center'><input onclick='toggleSelectRow2(this);' |
423 | dojoType=\"dijit.form.CheckBox\" type=\"checkbox\" | |
424 | id=\"UMCHK-$uid\"></td>"; | |
66665fba AD |
425 | |
426 | $onclick = "onclick='editUser($uid, event)' title='".__('Click to edit')."'"; | |
427 | ||
2f20dd58 | 428 | print "<td $onclick><img src='images/user.png' class='markedPic' alt=''> " . $line["login"] . "</td>"; |
66665fba AD |
429 | |
430 | if (!$line["email"]) $line["email"] = " "; | |
431 | ||
432 | print "<td $onclick>" . $access_level_names[$line["access_level"]] . "</td>"; | |
1edff0d4 | 433 | print "<td $onclick>" . $line["num_feeds"] . "</td>"; |
66665fba AD |
434 | print "<td $onclick>" . $line["created"] . "</td>"; |
435 | print "<td $onclick>" . $line["last_login"] . "</td>"; | |
436 | ||
437 | print "</tr>"; | |
438 | ||
439 | ++$lnum; | |
440 | } | |
441 | ||
442 | print "</table>"; | |
443 | ||
c2418a55 | 444 | if ($lnum == 0) { |
66665fba AD |
445 | if (!$user_search) { |
446 | print_warning(__('No users defined.')); | |
447 | } else { | |
448 | print_warning(__('No matching users found.')); | |
449 | } | |
66665fba AD |
450 | } |
451 | ||
452 | print "</div>"; #pane | |
6065f3ad | 453 | |
1ffe3391 | 454 | PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, |
6065f3ad AD |
455 | "hook_prefs_tab", "prefUsers"); |
456 | ||
66665fba AD |
457 | print "</div>"; #container |
458 | ||
459 | } | |
57932e18 | 460 | } |