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 2019-06-27 08:12:15 -05:00
parent ee3f53e108
commit 0fa2adfdd5
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(); $page = class_exists("CustomPage") ? new CustomPage() : new Page();
$_tracer->end(); $_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 // hook up event handlers
$_tracer->begin("Loading extensions"); $_tracer->begin("Loading extensions");
_load_event_listeners(); _load_event_listeners();

View file

@ -20,6 +20,11 @@ interface Config
*/ */
public function set_int(string $name, ?string $value): void; 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. * 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; 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. * 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; 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. * 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); $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 public function set_string(string $name, ?string $value): void
{ {
$this->values[$name] = $value; $this->values[$name] = $value;
@ -131,9 +157,13 @@ abstract class BaseConfig implements Config
$this->save($name); $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); $this->save($name);
} }
@ -279,19 +309,41 @@ class DatabaseConfig extends BaseConfig
/** @var Database */ /** @var Database */
private $database = null; 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->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) { if ($cached) {
$this->values = $cached; $this->values = $cached;
} else { } else {
$this->values = []; $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->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); $this->save($name);
} }
} else { } else {
$this->database->Execute("DELETE FROM config WHERE name = :name", ["name"=>$name]); $query = "DELETE FROM {$this->table_name} WHERE name = :name";
$this->database->Execute("INSERT INTO config VALUES (:name, :value)", ["name"=>$name, "value"=>$this->values[$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 // rather than deleting and having some other request(s) do a thundering
// herd of race-conditioned updates, just save the updated version once here // 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); $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 class UserPageBuildingEvent extends Event
{ {
/** @var User */ /** @var User */
@ -254,6 +265,17 @@ class UserPage extends Extension
ksort($event->stats); ksort($event->stats);
$this->theme->display_user_page($event->display_user, $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) { if ($user->id == $event->display_user->id) {
$ubbe = new UserBlockBuildingEvent(); $ubbe = new UserBlockBuildingEvent();
send_event($ubbe); send_event($ubbe);

View file

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

View file

@ -90,7 +90,6 @@ $_tracer->begin($_SERVER["REQUEST_URI"] ?? "No Request");
try { try {
// start the page generation waterfall // start the page generation waterfall
$user = _get_user();
if (PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { if (PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') {
send_event(new CommandEvent($argv)); send_event(new CommandEvent($argv));
} else { } else {