From 8f0aa8a4ca828d86b5d061b7d2c4fa6142aff117 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 26 Jun 2019 22:11:53 -0500 Subject: [PATCH] Added $user_config global based on existing config object for storing user-specific settings. Added event to the user page so that extensions can hook into it, providing user-specific setting controls --- core/_bootstrap.php | 5 +++ core/config.php | 83 +++++++++++++++++++++++++++++++++++++++----- ext/upgrade/main.php | 17 +++++++++ ext/user/main.php | 22 ++++++++++++ ext/user/theme.php | 21 ++++++----- index.php | 1 - 6 files changed, 129 insertions(+), 20 deletions(-) diff --git a/core/_bootstrap.php b/core/_bootstrap.php index a003ed6e..c9869a36 100644 --- a/core/_bootstrap.php +++ b/core/_bootstrap.php @@ -52,6 +52,11 @@ unset($themelet); $page = class_exists("CustomPage") ? new CustomPage() : new Page(); $_tracer->end(); +$_shm_ctx->log_start("Loading user information"); +$user = _get_user(); +$user_config = new DatabaseConfig($database, "user_config","user_id", $user->id); +$_shm_ctx->log_endok(); + // hook up event handlers $_tracer->begin("Loading extensions"); _load_event_listeners(); diff --git a/core/config.php b/core/config.php index c9fb225b..6b1ac6fa 100644 --- a/core/config.php +++ b/core/config.php @@ -20,6 +20,11 @@ interface Config */ public function set_int(string $name, ?string $value): void; + /** + * Set a configuration option to a new value, regardless of what the value is at the moment. + */ + public function set_float(string $name, ?string $value): void; + /** * Set a configuration option to a new value, regardless of what the value is at the moment. */ @@ -48,6 +53,16 @@ interface Config */ public function set_default_int(string $name, int $value): void; + /** + * Set a configuration option to a new value, if there is no value currently. + * + * Extensions should generally call these from their InitExtEvent handlers. + * This has the advantage that the values will show up in the "advanced" setup + * page where they can be modified, while calling get_* with a "default" + * parameter won't show up. + */ + public function set_default_float(string $name, float $value): void; + /** * Set a configuration option to a new value, if there is no value currently. * @@ -85,6 +100,11 @@ interface Config */ public function get_int(string $name, ?int $default=null): ?int; + /** + * Pick a value out of the table by name, cast to the appropriate data type. + */ + public function get_float(string $name, ?float $default=null): ?float; + /** * Pick a value out of the table by name, cast to the appropriate data type. */ @@ -119,6 +139,12 @@ abstract class BaseConfig implements Config $this->save($name); } + public function set_float(string $name, ?string $value): void + { + $this->values[$name] = $value; + $this->save($name); + } + public function set_string(string $name, ?string $value): void { $this->values[$name] = $value; @@ -131,9 +157,13 @@ abstract class BaseConfig implements Config $this->save($name); } - public function set_array(string $name, array $value): void + public function set_array(string $name, ?array $value): void { - $this->values[$name] = implode(",", $value); + if($value!=null) { + $this->values[$name] = implode(",", $value); + } else { + $this->values[$name] = null; + } $this->save($name); } @@ -279,19 +309,41 @@ class DatabaseConfig extends BaseConfig /** @var Database */ private $database = null; - public function __construct(Database $database) + private $table_name; + private $sub_column; + private $sub_value; + + public function __construct(Database $database, string $table_name = "config", + string $sub_column = null, string $sub_value = null) { $this->database = $database; + $this->table_name = $table_name; + $this->sub_value = $sub_value; + $this->sub_column = $sub_column; - $cached = $this->database->cache->get("config"); + $cache_name = "config"; + if(!empty($sub_value)) { + $cache_name .= "_".$sub_value; + } + + $cached = $this->database->cache->get($cache_name); if ($cached) { $this->values = $cached; } else { $this->values = []; - foreach ($this->database->get_all("SELECT name, value FROM config") as $row) { + + $query = "SELECT name, value FROM {$this->table_name}"; + $args = []; + + if(!empty($sub_column)&&!empty($sub_value)) { + $query .= " WHERE $sub_column = :sub_value"; + $args["sub_value"] = $sub_value; + } + + foreach ($this->database->get_all($query, $args ) as $row) { $this->values[$row["name"]] = $row["value"]; } - $this->database->cache->set("config", $this->values); + $this->database->cache->set($cache_name, $this->values); } } @@ -303,8 +355,23 @@ class DatabaseConfig extends BaseConfig $this->save($name); } } else { - $this->database->Execute("DELETE FROM config WHERE name = :name", ["name"=>$name]); - $this->database->Execute("INSERT INTO config VALUES (:name, :value)", ["name"=>$name, "value"=>$this->values[$name]]); + $query = "DELETE FROM {$this->table_name} WHERE name = :name"; + $args = ["name"=>$name]; + $cols = ["name","value"]; + $params = [":name",":value"]; + if(!empty($this->sub_column)&&!empty($this->sub_value)) { + $query .= " AND $this->sub_column = :sub_value"; + $args["sub_value"] = $this->sub_value; + $cols[] = $this->sub_column; + $params[] = ":sub_value"; + } + + $this->database->Execute($query, $args); + + $args["value"] =$this->values[$name]; + $this->database->Execute( + "INSERT INTO {$this->table_name} (".join(",",$cols).") VALUES (".join(",",$params).")", + $args); } // rather than deleting and having some other request(s) do a thundering // herd of race-conditioned updates, just save the updated version once here diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 3bad2d52..2ea12cb9 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -224,7 +224,24 @@ class Upgrade extends Extension $config->set_bool("in_upgrade", false); } + if ($config->get_int("db_version") < 18) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 18); + log_info("upgrade", "Adding user config table"); + + $database->create_table("user_config", " + user_id INTEGER NOT NULL, + name VARCHAR(128) NOT NULL, + value TEXT, + PRIMARY KEY (user_id, name), + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + "); + $database->execute("CREATE INDEX user_config_user_id_idx ON user_config(user_id)"); + + log_info("upgrade", "Database at version 18"); + $config->set_bool("in_upgrade", false); + } } diff --git a/ext/user/main.php b/ext/user/main.php index 4bb726d0..d6a59f8d 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -19,6 +19,17 @@ class UserBlockBuildingEvent extends Event } } +class UserOptionsBuildingEvent extends Event +{ + /** @var array */ + public $parts = []; + + public function add__html(string $html) + { + $this->parts[] = $html; + } +} + class UserPageBuildingEvent extends Event { /** @var User */ @@ -254,6 +265,17 @@ class UserPage extends Extension ksort($event->stats); $this->theme->display_user_page($event->display_user, $event->stats); + + if (!$user->is_anonymous()) { + if ($user->id == $event->display_user->id || $user->can("edit_user_info")) { + $uobe = new UserOptionsBuildingEvent(); + send_event($uobe); + + $page->add_block(new Block("Options", $this->theme->build_options($event->display_user, $uobe), "main", 60)); + } + } + + if ($user->id == $event->display_user->id) { $ubbe = new UserBlockBuildingEvent(); send_event($ubbe); diff --git a/ext/user/theme.php b/ext/user/theme.php index dab26e8c..a1650db4 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -243,14 +243,9 @@ class UserPageTheme extends Themelet $page->add_block(new NavBlock()); $page->add_block(new Block("Stats", join("
", $stats), "main", 10)); - if (!$user->is_anonymous()) { - if ($user->id == $duser->id || $user->can("edit_user_info")) { - $page->add_block(new Block("Options", $this->build_options($duser), "main", 60)); - } - } } - protected function build_options(User $duser) + public function build_options(User $duser, UserOptionsBuildingEvent $event) { global $config, $user; $html = ""; @@ -266,7 +261,7 @@ class UserPageTheme extends Themelet - "; +

"; } $html .= " @@ -285,7 +280,7 @@ class UserPageTheme extends Themelet - +

".make_form(make_link("user_admin/change_email"))." @@ -294,7 +289,7 @@ class UserPageTheme extends Themelet
- "; +

"; $i_user_id = int_escape($duser->id); @@ -316,7 +311,7 @@ class UserPageTheme extends Themelet - "; +

"; } if ($user->can(Permissions::DELETE_USER)) { @@ -337,8 +332,12 @@ class UserPageTheme extends Themelet - "; +

"; } + foreach ($event->parts as $part) { + $html .= $part; + } + } return $html; } diff --git a/index.php b/index.php index fdde0b16..95300516 100644 --- a/index.php +++ b/index.php @@ -90,7 +90,6 @@ $_tracer->begin($_SERVER["REQUEST_URI"] ?? "No Request"); try { // start the page generation waterfall - $user = _get_user(); if (PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { send_event(new CommandEvent($argv)); } else {