Added optional string role IDs for the API.
This commit is contained in:
parent
f373690b12
commit
aabffb7b30
6 changed files with 125 additions and 39 deletions
database
public-legacy/manage/users
src/Users
templates/manage/users
13
database/2024_09_16_205613_add_role_id_string.php
Normal file
13
database/2024_09_16_205613_add_role_id_string.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\Migration\IDbMigration;
|
||||||
|
|
||||||
|
final class AddRoleIdString_20240916_205613 implements IDbMigration {
|
||||||
|
public function migrate(IDbConnection $conn): void {
|
||||||
|
$conn->execute(<<<SQL
|
||||||
|
ALTER TABLE msz_roles
|
||||||
|
ADD COLUMN role_string VARCHAR(20) NULL DEFAULT NULL COLLATE 'ascii_general_ci' AFTER role_id,
|
||||||
|
ADD UNIQUE INDEX roles_string_unique (role_string);
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$roleString = (string)filter_input(INPUT_POST, 'ur_string');
|
||||||
$roleName = (string)filter_input(INPUT_POST, 'ur_name');
|
$roleName = (string)filter_input(INPUT_POST, 'ur_name');
|
||||||
$roleHide = !empty($_POST['ur_hidden']);
|
$roleHide = !empty($_POST['ur_hidden']);
|
||||||
$roleLeavable = !empty($_POST['ur_leavable']);
|
$roleLeavable = !empty($_POST['ur_leavable']);
|
||||||
|
@ -54,6 +55,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
$colourBlue = (int)filter_input(INPUT_POST, 'ur_col_blue', FILTER_SANITIZE_NUMBER_INT);
|
$colourBlue = (int)filter_input(INPUT_POST, 'ur_col_blue', FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
|
||||||
Template::set([
|
Template::set([
|
||||||
|
'role_ur_string' => $roleString,
|
||||||
'role_ur_name' => $roleName,
|
'role_ur_name' => $roleName,
|
||||||
'role_ur_hidden' => $roleHide,
|
'role_ur_hidden' => $roleHide,
|
||||||
'role_ur_leavable' => $roleLeavable,
|
'role_ur_leavable' => $roleLeavable,
|
||||||
|
@ -96,11 +98,31 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strlen($roleString) > 20) {
|
||||||
|
echo 'Role string may not be longer than 20 characters.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strlen($roleString) > 1 && !ctype_alpha($roleString[0])) {
|
||||||
|
echo 'Role string most start with an alphabetical character.';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if($isNew) {
|
if($isNew) {
|
||||||
$roleInfo = $roles->createRole($roleName, $roleRank, $roleColour, $roleTitle, $roleDesc, $roleHide, $roleLeavable);
|
$roleInfo = $roles->createRole(
|
||||||
|
$roleName,
|
||||||
|
$roleRank,
|
||||||
|
$roleColour,
|
||||||
|
string: $roleString,
|
||||||
|
title: $roleTitle,
|
||||||
|
description: $roleDesc,
|
||||||
|
hidden: $roleHide,
|
||||||
|
leavable: $roleLeavable
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if($roleName === $roleInfo->getName())
|
if($roleName === $roleInfo->getName())
|
||||||
$roleName = null;
|
$roleName = null;
|
||||||
|
if($roleString === $roleInfo->getString())
|
||||||
|
$roleString = null;
|
||||||
if($roleHide === $roleInfo->isHidden())
|
if($roleHide === $roleInfo->isHidden())
|
||||||
$roleHide = null;
|
$roleHide = null;
|
||||||
if($roleLeavable === $roleInfo->isLeavable())
|
if($roleLeavable === $roleInfo->isLeavable())
|
||||||
|
@ -115,7 +137,17 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
if((string)$roleColour === (string)$roleInfo->getColour())
|
if((string)$roleColour === (string)$roleInfo->getColour())
|
||||||
$roleColour = null;
|
$roleColour = null;
|
||||||
|
|
||||||
$roles->updateRole($roleInfo, $roleName, $roleRank, $roleColour, $roleTitle, $roleDesc, $roleHide, $roleLeavable);
|
$roles->updateRole(
|
||||||
|
$roleInfo,
|
||||||
|
string: $roleString,
|
||||||
|
name: $roleName,
|
||||||
|
rank: $roleRank,
|
||||||
|
colour: $roleColour,
|
||||||
|
title: $roleTitle,
|
||||||
|
description: $roleDesc,
|
||||||
|
hidden: $roleHide,
|
||||||
|
leavable: $roleLeavable
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$msz->createAuditLog(
|
$msz->createAuditLog(
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Index\Data\IDbResult;
|
||||||
class RoleInfo implements Stringable {
|
class RoleInfo implements Stringable {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private string $id,
|
private string $id,
|
||||||
|
private ?string $string,
|
||||||
private int $rank,
|
private int $rank,
|
||||||
private string $name,
|
private string $name,
|
||||||
private ?string $title,
|
private ?string $title,
|
||||||
|
@ -22,14 +23,15 @@ class RoleInfo implements Stringable {
|
||||||
public static function fromResult(IDbResult $result): RoleInfo {
|
public static function fromResult(IDbResult $result): RoleInfo {
|
||||||
return new RoleInfo(
|
return new RoleInfo(
|
||||||
id: $result->getString(0),
|
id: $result->getString(0),
|
||||||
rank: $result->getInteger(1),
|
string: $result->getStringOrNull(1),
|
||||||
name: $result->getString(2),
|
rank: $result->getInteger(2),
|
||||||
title: $result->getStringOrNull(3),
|
name: $result->getString(3),
|
||||||
description: $result->getStringOrNull(4),
|
title: $result->getStringOrNull(4),
|
||||||
hidden: $result->getBoolean(5),
|
description: $result->getStringOrNull(5),
|
||||||
leavable: $result->getBoolean(6),
|
hidden: $result->getBoolean(6),
|
||||||
colour: $result->getIntegerOrNull(7),
|
leavable: $result->getBoolean(7),
|
||||||
created: $result->getInteger(8),
|
colour: $result->getIntegerOrNull(8),
|
||||||
|
created: $result->getInteger(9),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +43,14 @@ class RoleInfo implements Stringable {
|
||||||
return $this->id === Roles::DEFAULT_ROLE;
|
return $this->id === Roles::DEFAULT_ROLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasString(): bool {
|
||||||
|
return $this->string !== null && $this->string !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(): ?string {
|
||||||
|
return $this->string;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRank(): int {
|
public function getRank(): int {
|
||||||
return $this->rank;
|
return $this->rank;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ class Roles {
|
||||||
public function getRoles(
|
public function getRoles(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
?bool $hidden = null,
|
?bool $hidden = null,
|
||||||
|
?bool $hasString = null,
|
||||||
|
bool $orderByRank = false,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): iterable {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
|
@ -67,23 +69,26 @@ class Roles {
|
||||||
$hasPagination = $pagination !== null;
|
$hasPagination = $pagination !== null;
|
||||||
|
|
||||||
$args = 0;
|
$args = 0;
|
||||||
$query = 'SELECT role_id, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles';
|
$query = 'SELECT role_id, role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles';
|
||||||
if($hasUserInfo) {
|
if($hasUserInfo) {
|
||||||
++$args;
|
++$args;
|
||||||
$query .= ' WHERE role_id IN (SELECT role_id FROM msz_users_roles WHERE user_id = ?)';
|
$query .= ' WHERE role_id IN (SELECT role_id FROM msz_users_roles WHERE user_id = ?)';
|
||||||
}
|
}
|
||||||
if($hasHidden)
|
if($hasHidden)
|
||||||
$query .= sprintf(' %s role_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
|
$query .= sprintf(' %s role_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
|
||||||
|
if($hasString)
|
||||||
|
$query .= sprintf(' %s role_string %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $hasString ? 'IS NOT' : 'IS');
|
||||||
|
if($orderByRank)
|
||||||
|
$query .= ' ORDER BY role_hierarchy DESC';
|
||||||
if($hasPagination)
|
if($hasPagination)
|
||||||
$query .= ' LIMIT ? OFFSET ?';
|
$query .= ' LIMIT ? OFFSET ?';
|
||||||
|
|
||||||
$args = 0;
|
|
||||||
$stmt = $this->cache->get($query);
|
$stmt = $this->cache->get($query);
|
||||||
if($hasUserInfo)
|
if($hasUserInfo)
|
||||||
$stmt->addParameter(++$args, $userInfo);
|
$stmt->nextParameter($userInfo);
|
||||||
if($hasPagination) {
|
if($hasPagination) {
|
||||||
$stmt->addParameter(++$args, $pagination->getRange());
|
$stmt->nextParameter($pagination->getRange());
|
||||||
$stmt->addParameter(++$args, $pagination->getOffset());
|
$stmt->nextParameter($pagination->getOffset());
|
||||||
}
|
}
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
|
@ -91,7 +96,7 @@ class Roles {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRole(string $roleId): RoleInfo {
|
public function getRole(string $roleId): RoleInfo {
|
||||||
$stmt = $this->cache->get('SELECT role_id, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles WHERE role_id = ?');
|
$stmt = $this->cache->get('SELECT role_id, role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles WHERE role_id = ?');
|
||||||
$stmt->addParameter(1, $roleId);
|
$stmt->addParameter(1, $roleId);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
|
@ -106,6 +111,7 @@ class Roles {
|
||||||
string $name,
|
string $name,
|
||||||
int $rank,
|
int $rank,
|
||||||
Colour $colour,
|
Colour $colour,
|
||||||
|
string $string = '',
|
||||||
string $title = '',
|
string $title = '',
|
||||||
string $description = '',
|
string $description = '',
|
||||||
bool $hidden = false,
|
bool $hidden = false,
|
||||||
|
@ -113,18 +119,22 @@ class Roles {
|
||||||
): RoleInfo {
|
): RoleInfo {
|
||||||
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
||||||
|
|
||||||
|
if($string === '')
|
||||||
|
$string = null;
|
||||||
|
|
||||||
// should these continue to accept NULL?
|
// should these continue to accept NULL?
|
||||||
if($title === '') $title = null;
|
if($title === '') $title = null;
|
||||||
if($description === '') $description = null;
|
if($description === '') $description = null;
|
||||||
|
|
||||||
$stmt = $this->cache->get('INSERT INTO msz_roles (role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
$stmt = $this->cache->get('INSERT INTO msz_roles (role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
||||||
$stmt->addParameter(1, $rank);
|
$stmt->nextParameter($string);
|
||||||
$stmt->addParameter(2, $name);
|
$stmt->nextParameter($rank);
|
||||||
$stmt->addParameter(3, $title);
|
$stmt->nextParameter($name);
|
||||||
$stmt->addParameter(4, $description);
|
$stmt->nextParameter($title);
|
||||||
$stmt->addParameter(5, $hidden ? 1 : 0);
|
$stmt->nextParameter($description);
|
||||||
$stmt->addParameter(6, $leavable ? 1 : 0);
|
$stmt->nextParameter($hidden ? 1 : 0);
|
||||||
$stmt->addParameter(7, $colour);
|
$stmt->nextParameter($leavable ? 1 : 0);
|
||||||
|
$stmt->nextParameter($colour);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
return $this->getRole((string)$this->dbConn->getLastInsertId());
|
return $this->getRole((string)$this->dbConn->getLastInsertId());
|
||||||
|
@ -156,6 +166,7 @@ class Roles {
|
||||||
|
|
||||||
public function updateRole(
|
public function updateRole(
|
||||||
RoleInfo|string $roleInfo,
|
RoleInfo|string $roleInfo,
|
||||||
|
?string $string = null,
|
||||||
?string $name = null,
|
?string $name = null,
|
||||||
?int $rank = null,
|
?int $rank = null,
|
||||||
?Colour $colour = null,
|
?Colour $colour = null,
|
||||||
|
@ -167,6 +178,7 @@ class Roles {
|
||||||
if($roleInfo instanceof RoleInfo)
|
if($roleInfo instanceof RoleInfo)
|
||||||
$roleInfo = $roleInfo->getId();
|
$roleInfo = $roleInfo->getId();
|
||||||
|
|
||||||
|
$applyString = $string !== null;
|
||||||
$applyTitle = $title !== null;
|
$applyTitle = $title !== null;
|
||||||
$applyDescription = $description !== null;
|
$applyDescription = $description !== null;
|
||||||
$applyColour = $colour !== null;
|
$applyColour = $colour !== null;
|
||||||
|
@ -176,24 +188,29 @@ class Roles {
|
||||||
if($applyColour)
|
if($applyColour)
|
||||||
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
||||||
|
|
||||||
|
if($string === '')
|
||||||
|
$string = null;
|
||||||
|
|
||||||
// should these continue to accept NULL?
|
// should these continue to accept NULL?
|
||||||
if($title === '') $title = null;
|
if($title === '') $title = null;
|
||||||
if($description === '') $description = null;
|
if($description === '') $description = null;
|
||||||
|
|
||||||
$stmt = $this->cache->get('UPDATE msz_roles SET role_hierarchy = COALESCE(?, role_hierarchy), role_name = COALESCE(?, role_name), role_title = IF(?, ?, role_title), role_description = IF(?, ?, role_description), role_hidden = IF(?, ?, role_hidden), role_can_leave = IF(?, ?, role_can_leave), role_colour = IF(?, ?, role_colour) WHERE role_id = ?');
|
$stmt = $this->cache->get('UPDATE msz_roles SET role_string = IF(?, ?, role_string), role_hierarchy = COALESCE(?, role_hierarchy), role_name = COALESCE(?, role_name), role_title = IF(?, ?, role_title), role_description = IF(?, ?, role_description), role_hidden = IF(?, ?, role_hidden), role_can_leave = IF(?, ?, role_can_leave), role_colour = IF(?, ?, role_colour) WHERE role_id = ?');
|
||||||
$stmt->addParameter(1, $rank);
|
$stmt->nextParameter($applyString ? 1 : 0);
|
||||||
$stmt->addParameter(2, $name);
|
$stmt->nextParameter($string);
|
||||||
$stmt->addParameter(3, $applyTitle ? 1 : 0);
|
$stmt->nextParameter($rank);
|
||||||
$stmt->addParameter(4, $title);
|
$stmt->nextParameter($name);
|
||||||
$stmt->addParameter(5, $applyDescription ? 1 : 0);
|
$stmt->nextParameter($applyTitle ? 1 : 0);
|
||||||
$stmt->addParameter(6, $description);
|
$stmt->nextParameter($title);
|
||||||
$stmt->addParameter(7, $applyHidden ? 1 : 0);
|
$stmt->nextParameter($applyDescription ? 1 : 0);
|
||||||
$stmt->addParameter(8, $hidden ? 1 : 0);
|
$stmt->nextParameter($description);
|
||||||
$stmt->addParameter(9, $applyLeavable ? 1 : 0);
|
$stmt->nextParameter($applyHidden ? 1 : 0);
|
||||||
$stmt->addParameter(10, $leavable ? 1 : 0);
|
$stmt->nextParameter($hidden ? 1 : 0);
|
||||||
$stmt->addParameter(11, $applyColour ? 1 : 0);
|
$stmt->nextParameter($applyLeavable ? 1 : 0);
|
||||||
$stmt->addParameter(12, $colour);
|
$stmt->nextParameter($leavable ? 1 : 0);
|
||||||
$stmt->addParameter(13, $roleInfo);
|
$stmt->nextParameter($applyColour ? 1 : 0);
|
||||||
|
$stmt->nextParameter($colour);
|
||||||
|
$stmt->nextParameter($roleInfo);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ use Misuzu\SiteInfo;
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\URLs\URLRegistry;
|
||||||
use Misuzu\Users\Assets\UserAvatarAsset;
|
use Misuzu\Users\Assets\UserAvatarAsset;
|
||||||
use Aiwass\Server\{RpcActionHandler,RpcQuery};
|
use Aiwass\Server\{RpcActionHandler,RpcQuery};
|
||||||
|
use Index\XArray;
|
||||||
use Index\Colour\{Colour,ColourRGB};
|
use Index\Colour\{Colour,ColourRGB};
|
||||||
|
|
||||||
final class UsersRpcActions extends RpcActionHandler {
|
final class UsersRpcActions extends RpcActionHandler {
|
||||||
|
@ -65,6 +66,13 @@ final class UsersRpcActions extends RpcActionHandler {
|
||||||
if($userInfo->hasLastActive())
|
if($userInfo->hasLastActive())
|
||||||
$output['last_active_at'] = $userInfo->getLastActiveAt()->toIso8601ZuluString();
|
$output['last_active_at'] = $userInfo->getLastActiveAt()->toIso8601ZuluString();
|
||||||
|
|
||||||
|
$roles = XArray::select(
|
||||||
|
$this->usersCtx->getRoles()->getRoles(userInfo: $userInfo, hasString: true, orderByRank: true),
|
||||||
|
fn($roleInfo) => $roleInfo->getString(),
|
||||||
|
);
|
||||||
|
if(!empty($roles))
|
||||||
|
$output['roles'] = $roles;
|
||||||
|
|
||||||
if($userInfo->hasTitle())
|
if($userInfo->hasTitle())
|
||||||
$output['title'] = $userInfo->getTitle();
|
$output['title'] = $userInfo->getTitle();
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label class="form__label">
|
||||||
|
<div class="form__label__text">Role String (used in API)</div>
|
||||||
|
<div class="form__label__input">
|
||||||
|
{{ input_text('ur_string', '', role_ur_string|default(role_info.string|default()), 'text', '', false, {'maxlength':20}) }}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
<label class="form__label">
|
<label class="form__label">
|
||||||
<div class="form__label__text">Hide Role</div>
|
<div class="form__label__text">Hide Role</div>
|
||||||
<div class="form__label__input">
|
<div class="form__label__input">
|
||||||
|
@ -44,7 +51,6 @@
|
||||||
{{ input_text('ur_title', '', role_ur_title|default(role_info.title|default()), 'text', '', false, {'maxlength':64}) }}
|
{{ input_text('ur_title', '', role_ur_title|default(role_info.title|default()), 'text', '', false, {'maxlength':64}) }}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue