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
This commit is contained in:
Matthew Barbour 2019-06-26 22:11:53 -05:00 committed by matthew
parent 8e3b8a7a1b
commit 8f0aa8a4ca
6 changed files with 129 additions and 20 deletions

View file

@ -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();

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);

View file

@ -243,14 +243,9 @@ class UserPageTheme extends Themelet
$page->add_block(new NavBlock());
$page->add_block(new Block("Stats", join("<br>", $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
<tfoot><tr><td colspan='2'><input type='Submit' value='Set'></td></tr></tfoot>
</table>
</form>
";
</p>";
}
$html .= "
@ -285,7 +280,7 @@ class UserPageTheme extends Themelet
</tfoot>
</table>
</form>
</p>
<p>".make_form(make_link("user_admin/change_email"))."
<input type='hidden' name='id' value='{$duser->id}'>
<table class='form'>
@ -294,7 +289,7 @@ class UserPageTheme extends Themelet
<tfoot><tr><td colspan='2'><input type='Submit' value='Set'></td></tr></tfoot>
</table>
</form>
";
</p>";
$i_user_id = int_escape($duser->id);
@ -316,7 +311,7 @@ class UserPageTheme extends Themelet
<tfoot><tr><td><input type='submit' value='Set'></td></tr></tfoot>
</table>
</form>
";
</p>";
}
if ($user->can(Permissions::DELETE_USER)) {
@ -337,8 +332,12 @@ class UserPageTheme extends Themelet
</tfoot>
</table>
</form>
";
</p>";
}
foreach ($event->parts as $part) {
$html .= $part;
}
}
return $html;
}

View file

@ -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 {