merge
This commit is contained in:
commit
ecb6266617
11 changed files with 305 additions and 388 deletions
18
composer.lock
generated
18
composer.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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", [
|
||||
|
|
|
@ -1,5 +1,27 @@
|
|||
<?php
|
||||
|
||||
use MicroCRUD\TextColumn;
|
||||
use MicroCRUD\Table;
|
||||
|
||||
class AliasTable extends Table
|
||||
{
|
||||
public function __construct(\FFSPHP\PDO $db)
|
||||
{
|
||||
parent::__construct($db);
|
||||
$this->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");
|
||||
|
|
|
@ -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 = "<th width='10%'>Action</th>";
|
||||
$h_add = "
|
||||
<tr>
|
||||
".make_form(make_link("alias/add"))."
|
||||
<td><input type='text' name='oldtag' class='autocomplete_tags' autocomplete='off'></td>
|
||||
<td><input type='text' name='newtag' class='autocomplete_tags' autocomplete='off'></td>
|
||||
<td><input type='submit' value='Add'></td>
|
||||
</form>
|
||||
</tr>
|
||||
";
|
||||
} else {
|
||||
$h_action = "";
|
||||
$h_add = "";
|
||||
}
|
||||
|
||||
$h_aliases = "";
|
||||
foreach ($aliases as $old => $new) {
|
||||
$h_old = html_escape($old);
|
||||
$h_new = "<a href='".make_link("post/list/".url_escape($new)."/1")."'>".html_escape($new)."</a>";
|
||||
|
||||
$h_aliases .= "<tr><td>$h_old</td><td>$h_new</td>";
|
||||
if ($can_manage) {
|
||||
$h_aliases .= "
|
||||
<td>
|
||||
".make_form(make_link("alias/remove"))."
|
||||
<input type='hidden' name='oldtag' value='$h_old'>
|
||||
<input type='submit' value='Remove'>
|
||||
</form>
|
||||
</td>
|
||||
";
|
||||
}
|
||||
$h_aliases .= "</tr>";
|
||||
}
|
||||
$html = "
|
||||
<table id='aliases' class='sortable zebra'>
|
||||
<thead><tr><th>From</th><th>To</th>$h_action</tr></thead>
|
||||
<tbody>$h_aliases</tbody>
|
||||
<tfoot>$h_add</tfoot>
|
||||
</table>
|
||||
$table
|
||||
$paginator
|
||||
<p><a href='".make_link("alias/export/aliases.csv")."' download='aliases.csv'>Download as CSV</a></p>
|
||||
";
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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', "<a href='$contact_link'>Contact the staff (be sure to include this message)</a>", $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', "<a href='$contact_link'>Contact the staff (be sure to include this message)</a>", $msg);
|
||||
} else {
|
||||
$msg = str_replace('$CONTACT', "", $msg);
|
||||
}
|
||||
$msg .= "<!-- $active_ban_id / {$row["mode"]} -->";
|
||||
|
||||
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:<br>(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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,74 @@
|
|||
<?php
|
||||
|
||||
use function MicroHTML\{A,SPAN};
|
||||
use MicroCRUD\Column;
|
||||
use MicroCRUD\DateTimeColumn;
|
||||
use MicroCRUD\TextColumn;
|
||||
use MicroCRUD\Table;
|
||||
|
||||
|
||||
class ActorColumn extends Column {
|
||||
public function __construct($name, $title)
|
||||
{
|
||||
parent::__construct($name, $title, "((username=:$name) OR (address=:$name))");
|
||||
}
|
||||
|
||||
public function display($row)
|
||||
{
|
||||
if ($row['username'] == "Anonymous") {
|
||||
return $row["address"];
|
||||
} else {
|
||||
return A(["href"=>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 "<a href='".make_link("post/view/$iid")."'>Image #$iid</a>";
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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 = "
|
||||
<style>
|
||||
.sizedinputs TD INPUT {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<table class='zebra'>
|
||||
<thead>
|
||||
<tr><th>Time</th><th>Module</th><th>User</th><th colspan='3'>Message</th></tr>
|
||||
".make_form("log/view", "GET")."
|
||||
<tr class='sizedinputs'>
|
||||
<td><input type='date' name='time-start' value='".$this->heie("time-start")."'>
|
||||
<br><input type='date' name='time-end' value='".$this->heie("time-end")."'></td>
|
||||
<td><input type='text' name='module' value='".$this->heie("module")."'></td>
|
||||
<td><input type='text' name='user' value='".$this->heie("user")."'></td>
|
||||
<td><input type='text' name='message' value='".$this->heie("message")."'></td>
|
||||
<td>
|
||||
<select name='priority'>
|
||||
<option value='".SCORE_LOG_DEBUG."' ".($this->heie("priority")==SCORE_LOG_DEBUG ? "selected" : "").">Debug</option>
|
||||
<option value='".SCORE_LOG_INFO."' ".($this->heie("priority")==SCORE_LOG_INFO ? "selected" : "").">Info</option>
|
||||
<option value='".SCORE_LOG_WARNING."' ".($this->heie("priority")==SCORE_LOG_WARNING ? "selected" : "").">Warning</option>
|
||||
<option value='".SCORE_LOG_ERROR."' ".($this->heie("priority")==SCORE_LOG_ERROR ? "selected" : "").">Error</option>
|
||||
<option value='".SCORE_LOG_CRITICAL."' ".($this->heie("priority")==SCORE_LOG_CRITICAL ? "selected" : "").">Critical</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type='submit' value='Search'></td>
|
||||
</tr>
|
||||
</form>
|
||||
</thead>
|
||||
<tbody>\n";
|
||||
reset($events); // rewind to first element in array.
|
||||
|
||||
foreach ($events as $event) {
|
||||
$c = $this->pri_to_col($event['priority']);
|
||||
$table .= "<tr style='color: $c'>";
|
||||
$table .= "<td>".str_replace(" ", " ", substr($event['date_sent'], 0, 19))."</td>";
|
||||
$table .= "<td>".$event['section']."</td>";
|
||||
if ($event['username'] == "Anonymous") {
|
||||
$table .= "<td>".$event['address']."</td>";
|
||||
} else {
|
||||
$table .= "<td><span title='".$event['address']."'>".
|
||||
"<a href='".make_link("user/".url_escape($event['username']))."'>".html_escape($event['username'])."</a>".
|
||||
"</span></td>";
|
||||
}
|
||||
$table .= "<td colspan='3'>".$this->scan_entities(html_escape($event['message']))."</td>";
|
||||
$table .= "</tr>\n";
|
||||
}
|
||||
$table .= "</tbody></table>";
|
||||
|
||||
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 "<a href='".make_link("post/view/$iid")."'>Image #$iid</a>";
|
||||
$page->add_block(new Block("Events", $table . $paginator));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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'])) {
|
||||
|
|
|
@ -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 = "<table class='zebra'>";
|
||||
|
||||
$html .= "<tr>";
|
||||
$html .= "<td>Name</td>";
|
||||
if ($user->can(Permissions::DELETE_USER)) {
|
||||
$html .= "<td>Email</td>";
|
||||
}
|
||||
$html .= "<td>Class</td>";
|
||||
$html .= "<td>Action</td>";
|
||||
$html .= "</tr>";
|
||||
|
||||
$h_username = html_escape(@$_GET['username']);
|
||||
$h_email = html_escape(@$_GET['email']);
|
||||
$h_class = html_escape(@$_GET['class']);
|
||||
|
||||
$html .= "<tr>" . make_form("user_admin/list", "GET");
|
||||
$html .= "<td><input type='text' name='username' value='$h_username'/></td>";
|
||||
if ($user->can(Permissions::DELETE_USER)) {
|
||||
$html .= "<td><input type='text' name='email' value='$h_email'/></td>";
|
||||
}
|
||||
$html .= "<td><input type='text' name='class' value='$h_class'/></td>";
|
||||
$html .= "<td><input type='submit' value='Search'/></td>";
|
||||
$html .= "</form></tr>";
|
||||
|
||||
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 .= "<tr>";
|
||||
$html .= "<td><a href='$u_link'>$h_name</a></td>";
|
||||
if ($user->can(Permissions::DELETE_USER)) {
|
||||
$html .= "<td>$h_email</td>";
|
||||
}
|
||||
$html .= "<td>$h_class</td>";
|
||||
$html .= "<td><a href='$u_posts'>Show Posts</a></td>";
|
||||
$html .= "</tr>";
|
||||
}
|
||||
|
||||
$html .= "</table>";
|
||||
|
||||
$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"))."
|
||||
<table style='width: 100%;' class='form'>
|
||||
|
@ -187,7 +111,7 @@ class UserPageTheme extends Themelet
|
|||
</table>
|
||||
</form>
|
||||
";
|
||||
if ($config->get_bool("login_signup_enabled")) {
|
||||
if ($config->get_bool("login_signup_enabled") && $user->can(Permissions::CREATE_USER)) {
|
||||
$html .= "<small><a href='".make_link("user_admin/create")."'>Create Account</a></small>";
|
||||
}
|
||||
$page->add_block(new Block("Login", $html, "left", 90));
|
||||
|
|
Reference in a new issue