diff --git a/composer.lock b/composer.lock index dd97dbb2..c5f59c31 100644 --- a/composer.lock +++ b/composer.lock @@ -342,16 +342,16 @@ }, { "name": "shish/ffsphp", - "version": "v0.0.1", + "version": "v0.0.2", "source": { "type": "git", "url": "https://github.com/shish/ffsphp.git", - "reference": "6b1874cf05b0b6bbdf7b118ca081097d1f830cd7" + "reference": "16c98d57c80bb4848f20253c8c1e5fe7f6c5823f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/shish/ffsphp/zipball/6b1874cf05b0b6bbdf7b118ca081097d1f830cd7", - "reference": "6b1874cf05b0b6bbdf7b118ca081097d1f830cd7", + "url": "https://api.github.com/repos/shish/ffsphp/zipball/16c98d57c80bb4848f20253c8c1e5fe7f6c5823f", + "reference": "16c98d57c80bb4848f20253c8c1e5fe7f6c5823f", "shasum": "" }, "require": { @@ -380,7 +380,7 @@ ], "description": "A collection of workarounds for stupid PHP things", "homepage": "https://github.com/shish/ffsphp", - "time": "2019-11-25T15:37:09+00:00" + "time": "2019-11-29T12:00:09+00:00" }, { "name": "shish/microcrud", @@ -429,7 +429,15 @@ "crud", "generator" ], +<<<<<<< HEAD "time": "2019-11-29T02:11:55+00:00" +======= +<<<<<<< HEAD + "time": "2019-11-29T21:15:17+00:00" +======= + "time": "2019-11-29T10:55:02+00:00" +>>>>>>> e926b15d5ffeb6f7c0510acacaaa846294212f5c +>>>>>>> 0a330cd0baebc7f9387fd63a36a88c38d4338a0f }, { "name": "shish/microhtml", diff --git a/core/permissions.php b/core/permissions.php index 84eb292e..a2eb842b 100644 --- a/core/permissions.php +++ b/core/permissions.php @@ -13,6 +13,7 @@ abstract class Permissions public const VIEW_IP = "view_ip"; # view IP addresses associated with things public const BAN_IP = "ban_ip"; + public const CREATE_USER = "create_user"; public const EDIT_USER_NAME = "edit_user_name"; public const EDIT_USER_PASSWORD = "edit_user_password"; public const EDIT_USER_INFO = "edit_user_info"; # email address, etc diff --git a/core/userclass.php b/core/userclass.php index e639167d..faf41bbe 100644 --- a/core/userclass.php +++ b/core/userclass.php @@ -83,6 +83,7 @@ new UserClass("base", null, [ Permissions::VIEW_IP => false, # view IP addresses associated with things Permissions::BAN_IP => false, + Permissions::CREATE_USER => false, Permissions::EDIT_USER_NAME => false, Permissions::EDIT_USER_PASSWORD => false, Permissions::EDIT_USER_INFO => false, # email address, etc @@ -163,6 +164,7 @@ new UserClass("ghost", "base", [ // Anonymous users can't do anything by default, but // the admin might grant them some permissions new UserClass("anonymous", "base", [ + Permissions::CREATE_USER => true, ]); new UserClass("user", "base", [ diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index 74fb02eb..8fadfd66 100644 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -1,5 +1,27 @@ table = "aliases"; + $this->base_query = "SELECT * FROM aliases"; + $this->primary_key = "oldtag"; + $this->size = 100; + $this->limit = 1000000; + $this->columns = [ + new TextColumn("oldtag", "Old Tag"), + new TextColumn("newtag", "New Tag"), + ]; + $this->order_by = ["oldtag"]; + $this->table_attrs = ["class" => "zebra"]; + } +} + class AddAliasEvent extends Event { /** @var string */ @@ -27,52 +49,36 @@ class AliasEditor extends Extension if ($event->page_matches("alias")) { if ($event->get_arg(0) == "add") { if ($user->can(Permissions::MANAGE_ALIAS_LIST)) { - if (isset($_POST['oldtag']) && isset($_POST['newtag'])) { - try { - $aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); - send_event($aae); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("alias/list")); - } catch (AddAliasException $ex) { - $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); - } + $user->ensure_authed(); + $input = validate_input(["c_oldtag"=>"string", "c_newtag"=>"string"]); + try { + $aae = new AddAliasEvent($input['c_oldtag'], $input['c_newtag']); + send_event($aae); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("alias/list")); + } catch (AddAliasException $ex) { + $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); } } } elseif ($event->get_arg(0) == "remove") { if ($user->can(Permissions::MANAGE_ALIAS_LIST)) { - if (isset($_POST['oldtag'])) { - $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $_POST['oldtag']]); - log_info("alias_editor", "Deleted alias for ".$_POST['oldtag'], "Deleted alias"); - - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("alias/list")); - } + $user->ensure_authed(); + $input = validate_input(["d_oldtag"=>"string"]); + $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $input['d_oldtag']]); + log_info("alias_editor", "Deleted alias for ".$input['d_oldtag'], "Deleted alias"); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("alias/list")); } } elseif ($event->get_arg(0) == "list") { - if ($event->count_args() == 2) { - $page_number = $event->get_arg(1); - if (!is_numeric($page_number)) { - $page_number = 0; - } elseif ($page_number <= 0) { - $page_number = 0; - } else { - $page_number--; - } - } else { - $page_number = 0; + $t = new AliasTable($database->raw_db()); + $t->token = $user->get_auth_token(); + $t->inputs = $_GET; + $t->size = $config->get_int('alias_items_per_page', 30); + if($user->can(Permissions::MANAGE_ALIAS_LIST)) { + $t->create_url = make_link("alias/add"); + $t->delete_url = make_link("alias/remove"); } - - $alias_per_page = $config->get_int('alias_items_per_page', 30); - - $query = "SELECT oldtag, newtag FROM aliases ORDER BY newtag ASC LIMIT :limit OFFSET :offset"; - $alias = $database->get_pairs( - $query, - ["limit"=>$alias_per_page, "offset"=>$page_number * $alias_per_page] - ); - - $total_pages = ceil($database->get_one("SELECT COUNT(*) FROM aliases") / $alias_per_page); - - $this->theme->display_aliases($alias, $page_number + 1, $total_pages); + $this->theme->display_aliases($t->table($t->query()), $t->paginator()); } elseif ($event->get_arg(0) == "export") { $page->set_mode(PageMode::DATA); $page->set_type("text/csv"); diff --git a/ext/alias_editor/theme.php b/ext/alias_editor/theme.php index 732139d4..3997e2f2 100644 --- a/ext/alias_editor/theme.php +++ b/ext/alias_editor/theme.php @@ -7,51 +7,14 @@ class AliasEditorTheme extends Themelet * * Note: $can_manage = whether things like "add new alias" should be shown */ - public function display_aliases(array $aliases, int $pageNumber, int $totalPages): void + public function display_aliases($table, $paginator): void { global $page, $user; $can_manage = $user->can(Permissions::MANAGE_ALIAS_LIST); - if ($can_manage) { - $h_action = "Action"; - $h_add = " - - ".make_form(make_link("alias/add"))." - - - - - - "; - } else { - $h_action = ""; - $h_add = ""; - } - - $h_aliases = ""; - foreach ($aliases as $old => $new) { - $h_old = html_escape($old); - $h_new = "".html_escape($new).""; - - $h_aliases .= "$h_old$h_new"; - if ($can_manage) { - $h_aliases .= " - - ".make_form(make_link("alias/remove"))." - - - - - "; - } - $h_aliases .= ""; - } $html = " - - $h_action - $h_aliases - $h_add -
FromTo
+ $table + $paginator

Download as CSV

"; @@ -69,7 +32,5 @@ class AliasEditorTheme extends Themelet if ($can_manage) { $page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51)); } - - $this->display_paginator($page, "alias/list", null, $pageNumber, $totalPages); } } diff --git a/ext/ipban/main.php b/ext/ipban/main.php index c059d7b7..1d1cd559 100644 --- a/ext/ipban/main.php +++ b/ext/ipban/main.php @@ -23,7 +23,12 @@ class IPBanTable extends Table $this->limit = 1000000; $this->columns = [ new InetColumn("ip", "IP"), - new EnumColumn("mode", "Mode", ["Block"=>"block", "Firewall"=>"firewall", "Ghost"=>"ghost"]), + new EnumColumn("mode", "Mode", [ + "Block"=>"block", + "Firewall"=>"firewall", + "Ghost"=>"ghost", + "Anon Ghost"=>"anon-ghost" + ]), new TextColumn("reason", "Reason"), new StringColumn("banner", "Banner"), new DateColumn("added", "Added"), @@ -35,7 +40,7 @@ class IPBanTable extends Table ]; $this->create_url = make_link("ip_ban/create"); $this->delete_url = make_link("ip_ban/delete"); - $this->table_attrs = ["class" => "zebra"]; + $this->table_attrs = ["class" => "zebra"]; } } @@ -88,95 +93,107 @@ class IPBan extends Extension { global $cache, $config, $database, $page, $user, $_shm_user_classes; - // Get lists of banned IPs and banned networks + // Get lists of banned IPs and banned networks $ips = $cache->get("ip_bans"); $networks = $cache->get("network_bans"); if ($ips === false || $networks === false) { - $rows = $database->get_pairs(" + $rows = $database->get_pairs(" SELECT ip, id FROM bans WHERE ((expires > CURRENT_TIMESTAMP) OR (expires IS NULL)) "); - $ips = []; # "0.0.0.0" => 123; - $networks = []; # "0.0.0.0/32" => 456; - foreach ($rows as $ip => $id) { - if (strstr($ip, '/')) { - $networks[$ip] = $id; - } else { - $ips[$ip] = $id; - } - } + $ips = []; # "0.0.0.0" => 123; + $networks = []; # "0.0.0.0/32" => 456; + foreach ($rows as $ip => $id) { + if (strstr($ip, '/')) { + $networks[$ip] = $id; + } else { + $ips[$ip] = $id; + } + } - $cache->set("ip_bans", $ips, 600); - $cache->set("network_bans", $networks, 600); + $cache->set("ip_bans", $ips, 60); + $cache->set("network_bans", $networks, 60); } - // Check if our current IP is in either of the ban lists + // Check if our current IP is in either of the ban lists $remote = $_SERVER['REMOTE_ADDR']; - $active_ban_id = null; + $active_ban_id = null; if (isset($ips[$remote])) { $active_ban_id = $ips[$remote]; + } else { + foreach ($networks as $range => $ban_id) { + if (ip_in_range($remote, $range)) { + $active_ban_id = $ban_id; + } + } } - else { - foreach ($networks as $range => $ban_id) { - if (ip_in_range($remote, $range)) { - $active_ban_id = $ban_id; - } - } - } - // If an active ban is found, act on it - if(!is_null($active_ban_id)) { - $row = $database->get_row("SELECT * FROM bans WHERE id=:id", ["id"=>$active_ban_id]); + // If an active ban is found, act on it + if (!is_null($active_ban_id)) { + $row = $database->get_row("SELECT * FROM bans WHERE id=:id", ["id"=>$active_ban_id]); + if (empty($row)) { + return; + } - $msg = $config->get_string("ipban_message"); - $msg = str_replace('$IP', $row["ip"], $msg); - $msg = str_replace('$DATE', $row['expires'], $msg); - $msg = str_replace('$ADMIN', User::by_id($row['banner_id'])->name, $msg); - $msg = str_replace('$REASON', $row['reason'], $msg); - $contact_link = contact_link(); - if (!empty($contact_link)) { - $msg = str_replace('$CONTACT', "Contact the staff (be sure to include this message)", $msg); - } else { - $msg = str_replace('$CONTACT', "", $msg); - } + $msg = $config->get_string("ipban_message_{$row['mode']}") ?? $config->get_string("ipban_message"); + $msg = str_replace('$IP', $row["ip"], $msg); + $msg = str_replace('$DATE', $row['expires'] ?? 'the end of time', $msg); + $msg = str_replace('$ADMIN', User::by_id($row['banner_id'])->name, $msg); + $msg = str_replace('$REASON', $row['reason'], $msg); + $contact_link = contact_link(); + if (!empty($contact_link)) { + $msg = str_replace('$CONTACT', "Contact the staff (be sure to include this message)", $msg); + } else { + $msg = str_replace('$CONTACT', "", $msg); + } + $msg .= ""; - if($row["mode"] == "ghost") { - $b = new Block(null, $msg, "main", 0); - $b->is_content = false; - $page->add_block($b); - $event->user->class = $_shm_user_classes["ghost"]; - } else { - header("HTTP/1.0 403 Forbidden"); - print "$msg"; - exit; - } - } + if ($row["mode"] == "ghost") { + $b = new Block(null, $msg, "main", 0); + $b->is_content = false; + $page->add_block($b); + $page->add_cookie("nocache", "Ghost Banned", time()+60*60*2, "/"); + $event->user->class = $_shm_user_classes["ghost"]; + } elseif ($row["mode"] == "anon-ghost") { + if ($event->user->is_anonymous()) { + $b = new Block(null, $msg, "main", 0); + $b->is_content = false; + $page->add_block($b); + $page->add_cookie("nocache", "Ghost Banned", time()+60*60*2, "/"); + $event->user->class = $_shm_user_classes["ghost"]; + } + } else { + header("HTTP/1.0 403 Forbidden"); + print "$msg"; + exit; + } + } } public function onPageRequest(PageRequestEvent $event) { if ($event->page_matches("ip_ban")) { - global $database, $page, $user; + global $database, $page, $user; if ($user->can(Permissions::BAN_IP)) { if ($event->get_arg(0) == "create") { - $user->ensure_authed(); - $input = validate_input(["c_ip"=>"string", "c_mode"=>"string", "c_reason"=>"string", "c_expires"=>"optional,date"]); - send_event(new AddIPBanEvent($input['c_ip'], $input['c_mode'], $input['c_reason'], $input['c_expires'])); - flash_message("Ban for {$input['c_ip']} added"); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("ip_ban/list")); + $user->ensure_authed(); + $input = validate_input(["c_ip"=>"string", "c_mode"=>"string", "c_reason"=>"string", "c_expires"=>"optional,date"]); + send_event(new AddIPBanEvent($input['c_ip'], $input['c_mode'], $input['c_reason'], $input['c_expires'])); + flash_message("Ban for {$input['c_ip']} added"); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("ip_ban/list")); } elseif ($event->get_arg(0) == "delete") { - $user->ensure_authed(); - $input = validate_input(["d_id"=>"int"]); - send_event(new RemoveIPBanEvent($input['d_id'])); - flash_message("Ban removed"); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(make_link("ip_ban/list")); + $user->ensure_authed(); + $input = validate_input(["d_id"=>"int"]); + send_event(new RemoveIPBanEvent($input['d_id'])); + flash_message("Ban removed"); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("ip_ban/list")); } elseif ($event->get_arg(0) == "list") { - $_GET['c_banner'] = $user->name; - $_GET['c_added'] = date('Y-m-d'); + $_GET['c_banner'] = $user->name; + $_GET['c_added'] = date('Y-m-d'); $t = new IPBanTable($database->raw_db()); $t->token = $user->get_auth_token(); $t->inputs = $_GET; @@ -190,8 +207,16 @@ class IPBan extends Extension public function onSetupBuilding(SetupBuildingEvent $event) { + global $config; + $sb = new SetupBlock("IP Ban"); $sb->add_longtext_option("ipban_message", 'Message to show to banned users:
(with $IP, $DATE, $ADMIN, $REASON, and $CONTACT)'); + if ($config->get_string("ipban_message_ghost")) { + $sb->add_longtext_option("ipban_message_ghost", 'Message to show to ghost users:'); + } + if ($config->get_string("ipban_message_anon-ghost")) { + $sb->add_longtext_option("ipban_message_anon-ghost", 'Message to show to ghost anons:'); + } $event->panel->add_block($sb); } @@ -218,7 +243,8 @@ class IPBan extends Extension global $cache, $user, $database; $sql = "INSERT INTO bans (ip, mode, reason, expires, banner_id) VALUES (:ip, :mode, :reason, :expires, :admin_id)"; $database->Execute($sql, ["ip"=>$event->ip, "mode"=>$event->mode, "reason"=>$event->reason, "expires"=>$event->expires, "admin_id"=>$user->id]); - $cache->delete("ip_bans_sorted"); + $cache->delete("ip_bans"); + $cache->delete("network_bans"); log_info("ipban", "Banned {$event->ip} because '{$event->reason}' until {$event->expires}"); } @@ -228,7 +254,8 @@ class IPBan extends Extension $ban = $database->get_row("SELECT * FROM bans WHERE id = :id", ["id"=>$event->id]); if ($ban) { $database->Execute("DELETE FROM bans WHERE id = :id", ["id"=>$event->id]); - $cache->delete("ip_bans_sorted"); + $cache->delete("ip_bans"); + $cache->delete("network_bans"); log_info("ipban", "Removed {$ban['ip']}'s ban"); } } diff --git a/ext/log_db/main.php b/ext/log_db/main.php index a8d5644a..2c652335 100644 --- a/ext/log_db/main.php +++ b/ext/log_db/main.php @@ -1,5 +1,74 @@ make_link("user/{$row['username']}"), "title"=>$row['address']], $row['username']); + } + } +} + +class MessageColumn extends TextColumn { + public function display($row) + { + $c = "#000"; + switch ($row['priority']) { + case SCORE_LOG_DEBUG: $c = "#999"; break; + case SCORE_LOG_INFO: $c = "#000"; break; + case SCORE_LOG_WARNING: $c = "#800"; break; + case SCORE_LOG_ERROR: $c = "#C00"; break; + case SCORE_LOG_CRITICAL: $c = "#F00"; break; + } + return SPAN(["style"=>"color: $c"], $this->scan_entities($row[$this->name])); + } + + protected function scan_entities($line) + { + return preg_replace_callback("/Image #(\d+)/s", [$this, "link_image"], $line); + } + + protected function link_image($id) + { + $iid = int_escape($id[1]); + return "Image #$iid"; + } +} + +class LogTable extends Table +{ + public function __construct(\FFSPHP\PDO $db) + { + parent::__construct($db); + $this->table = "score_log"; + $this->base_query = "SELECT * FROM score_log"; + $this->size = 100; + $this->limit = 1000000; + $this->columns = [ + new DateTimeColumn("date_sent", "Time"), + new TextColumn("section", "Module"), + new ActorColumn("username_or_address", "User"), + new MessageColumn("message", "Message") + ]; + $this->order_by = ["date_sent DESC"]; + $this->table_attrs = ["class" => "zebra"]; + } +} + class LogDatabase extends Extension { public function onInitExt(InitExtEvent $event) diff --git a/ext/log_db/theme.php b/ext/log_db/theme.php index 94d656b8..ee02dc86 100644 --- a/ext/log_db/theme.php +++ b/ext/log_db/theme.php @@ -2,133 +2,12 @@ class LogDatabaseTheme extends Themelet { - protected function heie($var) + public function display_events($table, $paginator) { - if (isset($_GET[$var])) { - return html_escape($_GET[$var]); - } else { - return ""; - } - } - - protected function ueie($var) - { - if (isset($_GET[$var])) { - return $var."=".url_escape($_GET[$var]); - } else { - return ""; - } - } - - public function display_events($events, $page_num, $page_total) - { - $table = " - - - - - ".make_form("log/view", "GET")." - - - - - - - - - - - \n"; - reset($events); // rewind to first element in array. - - foreach ($events as $event) { - $c = $this->pri_to_col($event['priority']); - $table .= ""; - $table .= ""; - $table .= ""; - if ($event['username'] == "Anonymous") { - $table .= ""; - } else { - $table .= ""; - } - $table .= ""; - $table .= "\n"; - } - $table .= "
TimeModuleUserMessage
-
- -
".str_replace(" ", " ", substr($event['date_sent'], 0, 19))."".$event['section']."".$event['address']."". - "".html_escape($event['username'])."". - "".$this->scan_entities(html_escape($event['message']))."
"; - global $page; $page->set_title("Event Log"); $page->set_heading("Event Log"); $page->add_block(new NavBlock()); - $page->add_block(new Block("Events", $table)); - $this->display_paginator($page, "log/view", $this->get_args(), $page_num, $page_total); - } - - protected function get_args() - { - $args = ""; - // Check if each arg is actually empty and skip it if so - if (strlen($this->ueie("time-start"))) { - $args .= $this->ueie("time-start")."&"; - } - if (strlen($this->ueie("time-end"))) { - $args .= $this->ueie("time-end")."&"; - } - if (strlen($this->ueie("module"))) { - $args .= $this->ueie("module")."&"; - } - if (strlen($this->ueie("user"))) { - $args .= $this->ueie("user")."&"; - } - if (strlen($this->ueie("message"))) { - $args .= $this->ueie("message")."&"; - } - if (strlen($this->ueie("priority"))) { - $args .= $this->ueie("priority"); - } - // If there are no args at all, set $args to null to prevent an unnecessary ? at the end of the paginator url - if (strlen($args) == 0) { - $args = null; - } - return $args; - } - - protected function pri_to_col($pri) - { - switch ($pri) { - case SCORE_LOG_DEBUG: return "#999"; - case SCORE_LOG_INFO: return "#000"; - case SCORE_LOG_WARNING: return "#800"; - case SCORE_LOG_ERROR: return "#C00"; - case SCORE_LOG_CRITICAL: return "#F00"; - default: return ""; - } - } - - protected function scan_entities($line) - { - $line = preg_replace_callback("/Image #(\d+)/s", [$this, "link_image"], $line); - return $line; - } - - protected function link_image($id) - { - $iid = int_escape($id[1]); - return "Image #$iid"; + $page->add_block(new Block("Events", $table . $paginator)); } } diff --git a/ext/source_history/main.php b/ext/source_history/main.php index 0afb0729..90edc8f0 100644 --- a/ext/source_history/main.php +++ b/ext/source_history/main.php @@ -373,7 +373,7 @@ class SourceHistory extends Extension " INSERT INTO source_histories(image_id, source, user_id, user_ip, date_set) VALUES (:image_id, :source, :user_id, :user_ip, now())", - ["image_id"=>$image->id, "source"=>$old_tags, "user_id"=>$config->get_int('anon_id'), "user_ip"=>'127.0.0.1'] + ["image_id"=>$image->id, "source"=>$old_source, "user_id"=>$config->get_int('anon_id'), "user_ip"=>'127.0.0.1'] ); $entries++; } diff --git a/ext/user/main.php b/ext/user/main.php index 9ac332e9..e690d148 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -2,6 +2,61 @@ require_once "events.php"; +use function MicroHTML\A; +use MicroCRUD\Column; +use MicroCRUD\EnumColumn; +use MicroCRUD\TextColumn; +use MicroCRUD\Table; + +class UserNameColumn extends TextColumn { + public function display(array $row) { + return A(["href"=>make_link("user/{$row[$this->name]}")], $row[$this->name]); + } +} + +class UserLinksColumn extends Column { + public function __construct() { + parent::__construct("links", "User Links", "(1=1)"); + $this->sortable = false; + } + public function create_input(array $inputs) { + return ""; + } + public function read_input(array $inputs) { + return ""; + } + public function display(array $row) { + return A(["href"=>make_link("post/list/user_id={$row['id']}/1")], "Posts"); + } +} + +class UserTable extends Table +{ + public function __construct(\FFSPHP\PDO $db) + { + global $_shm_user_classes; + $classes = []; + foreach($_shm_user_classes as $cls) { + $classes[$cls->name] = $cls->name; + } + ksort($classes); + parent::__construct($db); + $this->table = "users"; + $this->base_query = "SELECT * FROM users"; + $this->size = 100; + $this->limit = 1000000; + $this->columns = [ + new UserNameColumn("name", "Name"), + new EnumColumn("class", "Class", $classes), + // Added later, for admins only + // new TextColumn("email", "Email"), + new UserLinksColumn(), + ]; + $this->order_by = ["name"]; + $this->table_attrs = ["class" => "zebra"]; + } +} + class UserCreationException extends SCoreException { } @@ -51,36 +106,15 @@ class UserPage extends Extension } elseif ($event->get_arg(0) == "create") { $this->page_create(); } elseif ($event->get_arg(0) == "list") { - $limit = 50; - - $page_num = $event->try_page_num(1); - $offset = ($page_num-1) * $limit; - - $q = "WHERE 1=1"; - $a = []; - - if (@$_GET['username']) { - $q .= " AND SCORE_STRNORM(name) LIKE SCORE_STRNORM(:name)"; - $a["name"] = '%' . $_GET['username'] . '%'; + $t = new UserTable($database->raw_db()); + $t->token = $user->get_auth_token(); + $t->inputs = $_GET; + if ($user->can(Permissions::DELETE_USER)) { + $col = new TextColumn("email", "Email"); + // $t->columns[] = $col; + array_splice($t->columns, 2, 0, [$col]); } - - if ($user->can(Permissions::DELETE_USER) && @$_GET['email']) { - $q .= " AND SCORE_STRNORM(email) LIKE SCORE_STRNORM(:email)"; - $a["email"] = '%' . $_GET['email'] . '%'; - } - - if (@$_GET['class']) { - $q .= " AND class LIKE :class"; - $a["class"] = $_GET['class']; - } - $where = $database->scoreql_to_sql($q); - - $count = $database->get_one("SELECT count(*) FROM users $where", $a); - $a["offset"] = $offset; - $a["limit"] = $limit; - $rows = $database->get_all("SELECT * FROM users $where LIMIT :limit OFFSET :offset", $a); - $users = array_map("_new_user", $rows); - $this->theme->display_user_list($page, $users, $user, $page_num, $count/$limit); + $this->theme->display_user_list($page, $t->table($t->query()), $t->paginator()); } elseif ($event->get_arg(0) == "logout") { $this->page_logout(); } @@ -156,6 +190,9 @@ class UserPage extends Extension } $event->add_stats("Joined: $h_join_date", 10); + if($user->name == $event->display_user->name) { + $event->add_stats("Current IP: {$_SERVER['REMOTE_ADDR']}", 80); + } $event->add_stats("Class: $h_class", 90); $av = $event->display_user->get_avatar_html(); @@ -184,7 +221,6 @@ class UserPage extends Extension } } - private function display_stats(UserPageBuildingEvent $event) { global $user, $page, $config; @@ -201,7 +237,6 @@ class UserPage extends Extension } } - if ($user->id == $event->display_user->id) { $ubbe = new UserBlockBuildingEvent(); send_event($ubbe); @@ -397,7 +432,12 @@ class UserPage extends Extension private function page_create() { - global $config, $page; + global $config, $page, $user; + if ($user->can(Permissions::CREATE_USER)) { + $this->theme->display_error(403, "Account creation blocked", "Account creation is currently disabled"); + return; + } + if (!$config->get_bool("login_signup_enabled")) { $this->theme->display_signups_disabled($page); } elseif (!isset($_POST['name'])) { diff --git a/ext/user/theme.php b/ext/user/theme.php index 3c41641d..125fdacb 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -13,88 +13,12 @@ class UserPageTheme extends Themelet )); } - /** - * #param User[] $users - */ - public function display_user_list(Page $page, array $users, User $user, int $page_num, int $page_total) + public function display_user_list(Page $page, $table, $paginator) { $page->set_title("User List"); $page->set_heading("User List"); $page->add_block(new NavBlock()); - - $html = ""; - - $html .= ""; - $html .= ""; - if ($user->can(Permissions::DELETE_USER)) { - $html .= ""; - } - $html .= ""; - $html .= ""; - $html .= ""; - - $h_username = html_escape(@$_GET['username']); - $h_email = html_escape(@$_GET['email']); - $h_class = html_escape(@$_GET['class']); - - $html .= "" . make_form("user_admin/list", "GET"); - $html .= ""; - if ($user->can(Permissions::DELETE_USER)) { - $html .= ""; - } - $html .= ""; - $html .= ""; - $html .= ""; - - foreach ($users as $duser) { - $h_name = html_escape($duser->name); - $h_email = html_escape($duser->email); - $h_class = html_escape($duser->class->name); - $u_link = make_link("user/" . url_escape($duser->name)); - $u_posts = make_link("post/list/user_id=" . url_escape($duser->id) . "/1"); - - $html .= ""; - $html .= ""; - if ($user->can(Permissions::DELETE_USER)) { - $html .= ""; - } - $html .= ""; - $html .= ""; - $html .= ""; - } - - $html .= "
NameEmailClassAction
$h_name$h_email$h_classShow Posts
"; - - $page->add_block(new Block("Users", $html)); - $this->display_paginator($page, "user_admin/list", $this->get_args(), $page_num, $page_total); - } - - protected function ueie($var) - { - if (isset($_GET[$var])) { - return $var."=".url_escape($_GET[$var]); - } else { - return ""; - } - } - protected function get_args() - { - $args = ""; - // Check if each arg is actually empty and skip it if so - if (strlen($this->ueie("username"))) { - $args .= $this->ueie("username")."&"; - } - if (strlen($this->ueie("email"))) { - $args .= $this->ueie("email")."&"; - } - if (strlen($this->ueie("class"))) { - $args .= $this->ueie("class")."&"; - } - // If there are no args at all, set $args to null to prevent an unnecessary ? at the end of the paginator url - if (strlen($args) == 0) { - $args = null; - } - return $args; + $page->add_block(new Block("Users", $table . $paginator)); } public function display_user_links(Page $page, User $user, $parts) @@ -167,7 +91,7 @@ class UserPageTheme extends Themelet public function display_login_block(Page $page) { - global $config; + global $config, $user; $html = ' '.make_form(make_link("user_admin/login"))." @@ -187,7 +111,7 @@ class UserPageTheme extends Themelet
"; - if ($config->get_bool("login_signup_enabled")) { + if ($config->get_bool("login_signup_enabled") && $user->can(Permissions::CREATE_USER)) { $html .= "Create Account"; } $page->add_block(new Block("Login", $html, "left", 90));