Added optional string role IDs for the API.

This commit is contained in:
Pachira 2024-09-16 21:44:37 +00:00
parent 37a3bc1ee6
commit f8aaa71260
6 changed files with 125 additions and 39 deletions

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

View file

@ -42,6 +42,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
break;
}
$roleString = (string)filter_input(INPUT_POST, 'ur_string');
$roleName = (string)filter_input(INPUT_POST, 'ur_name');
$roleHide = !empty($_POST['ur_hidden']);
$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);
Template::set([
'role_ur_string' => $roleString,
'role_ur_name' => $roleName,
'role_ur_hidden' => $roleHide,
'role_ur_leavable' => $roleLeavable,
@ -96,11 +98,31 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
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) {
$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 {
if($roleName === $roleInfo->getName())
$roleName = null;
if($roleString === $roleInfo->getString())
$roleString = null;
if($roleHide === $roleInfo->isHidden())
$roleHide = null;
if($roleLeavable === $roleInfo->isLeavable())
@ -115,7 +137,17 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
if((string)$roleColour === (string)$roleInfo->getColour())
$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(

View file

@ -9,6 +9,7 @@ use Index\Data\IDbResult;
class RoleInfo implements Stringable {
public function __construct(
private string $id,
private ?string $string,
private int $rank,
private string $name,
private ?string $title,
@ -22,14 +23,15 @@ class RoleInfo implements Stringable {
public static function fromResult(IDbResult $result): RoleInfo {
return new RoleInfo(
id: $result->getString(0),
rank: $result->getInteger(1),
name: $result->getString(2),
title: $result->getStringOrNull(3),
description: $result->getStringOrNull(4),
hidden: $result->getBoolean(5),
leavable: $result->getBoolean(6),
colour: $result->getIntegerOrNull(7),
created: $result->getInteger(8),
string: $result->getStringOrNull(1),
rank: $result->getInteger(2),
name: $result->getString(3),
title: $result->getStringOrNull(4),
description: $result->getStringOrNull(5),
hidden: $result->getBoolean(6),
leavable: $result->getBoolean(7),
colour: $result->getIntegerOrNull(8),
created: $result->getInteger(9),
);
}
@ -41,6 +43,14 @@ class RoleInfo implements Stringable {
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 {
return $this->rank;
}

View file

@ -57,6 +57,8 @@ class Roles {
public function getRoles(
UserInfo|string|null $userInfo = null,
?bool $hidden = null,
?bool $hasString = null,
bool $orderByRank = false,
?Pagination $pagination = null
): iterable {
if($userInfo instanceof UserInfo)
@ -67,23 +69,26 @@ class Roles {
$hasPagination = $pagination !== null;
$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) {
++$args;
$query .= ' WHERE role_id IN (SELECT role_id FROM msz_users_roles WHERE user_id = ?)';
}
if($hasHidden)
$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)
$query .= ' LIMIT ? OFFSET ?';
$args = 0;
$stmt = $this->cache->get($query);
if($hasUserInfo)
$stmt->addParameter(++$args, $userInfo);
$stmt->nextParameter($userInfo);
if($hasPagination) {
$stmt->addParameter(++$args, $pagination->getRange());
$stmt->addParameter(++$args, $pagination->getOffset());
$stmt->nextParameter($pagination->getRange());
$stmt->nextParameter($pagination->getOffset());
}
$stmt->execute();
@ -91,7 +96,7 @@ class Roles {
}
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->execute();
@ -106,6 +111,7 @@ class Roles {
string $name,
int $rank,
Colour $colour,
string $string = '',
string $title = '',
string $description = '',
bool $hidden = false,
@ -113,18 +119,22 @@ class Roles {
): RoleInfo {
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
if($string === '')
$string = null;
// should these continue to accept NULL?
if($title === '') $title = 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->addParameter(1, $rank);
$stmt->addParameter(2, $name);
$stmt->addParameter(3, $title);
$stmt->addParameter(4, $description);
$stmt->addParameter(5, $hidden ? 1 : 0);
$stmt->addParameter(6, $leavable ? 1 : 0);
$stmt->addParameter(7, $colour);
$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->nextParameter($string);
$stmt->nextParameter($rank);
$stmt->nextParameter($name);
$stmt->nextParameter($title);
$stmt->nextParameter($description);
$stmt->nextParameter($hidden ? 1 : 0);
$stmt->nextParameter($leavable ? 1 : 0);
$stmt->nextParameter($colour);
$stmt->execute();
return $this->getRole((string)$this->dbConn->getLastInsertId());
@ -156,6 +166,7 @@ class Roles {
public function updateRole(
RoleInfo|string $roleInfo,
?string $string = null,
?string $name = null,
?int $rank = null,
?Colour $colour = null,
@ -167,6 +178,7 @@ class Roles {
if($roleInfo instanceof RoleInfo)
$roleInfo = $roleInfo->getId();
$applyString = $string !== null;
$applyTitle = $title !== null;
$applyDescription = $description !== null;
$applyColour = $colour !== null;
@ -176,24 +188,29 @@ class Roles {
if($applyColour)
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
if($string === '')
$string = null;
// should these continue to accept NULL?
if($title === '') $title = 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->addParameter(1, $rank);
$stmt->addParameter(2, $name);
$stmt->addParameter(3, $applyTitle ? 1 : 0);
$stmt->addParameter(4, $title);
$stmt->addParameter(5, $applyDescription ? 1 : 0);
$stmt->addParameter(6, $description);
$stmt->addParameter(7, $applyHidden ? 1 : 0);
$stmt->addParameter(8, $hidden ? 1 : 0);
$stmt->addParameter(9, $applyLeavable ? 1 : 0);
$stmt->addParameter(10, $leavable ? 1 : 0);
$stmt->addParameter(11, $applyColour ? 1 : 0);
$stmt->addParameter(12, $colour);
$stmt->addParameter(13, $roleInfo);
$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->nextParameter($applyString ? 1 : 0);
$stmt->nextParameter($string);
$stmt->nextParameter($rank);
$stmt->nextParameter($name);
$stmt->nextParameter($applyTitle ? 1 : 0);
$stmt->nextParameter($title);
$stmt->nextParameter($applyDescription ? 1 : 0);
$stmt->nextParameter($description);
$stmt->nextParameter($applyHidden ? 1 : 0);
$stmt->nextParameter($hidden ? 1 : 0);
$stmt->nextParameter($applyLeavable ? 1 : 0);
$stmt->nextParameter($leavable ? 1 : 0);
$stmt->nextParameter($applyColour ? 1 : 0);
$stmt->nextParameter($colour);
$stmt->nextParameter($roleInfo);
$stmt->execute();
}

View file

@ -6,6 +6,7 @@ use Misuzu\SiteInfo;
use Misuzu\URLs\URLRegistry;
use Misuzu\Users\Assets\UserAvatarAsset;
use Aiwass\Server\{RpcActionHandler,RpcQuery};
use Index\XArray;
use Index\Colour\{Colour,ColourRGB};
final class UsersRpcActions extends RpcActionHandler {
@ -65,6 +66,13 @@ final class UsersRpcActions extends RpcActionHandler {
if($userInfo->hasLastActive())
$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())
$output['title'] = $userInfo->getTitle();

View file

@ -17,6 +17,13 @@
</div>
</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">
<div class="form__label__text">Hide Role</div>
<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}) }}
</div>
</label>
</div>
<div class="container">