added user and roles controllers and unified naming

This commit is contained in:
root
2025-12-25 11:49:45 -05:00
parent 3d6aa856b4
commit 9f19ec1302
11 changed files with 833 additions and 23 deletions

View File

@@ -5,7 +5,7 @@ namespace KTXC\Stores;
use KTXC\Db\DataStore;
use KTXF\Utile\UUID;
class UserStore
class UserAccountsStore
{
public function __construct(protected DataStore $store)
@@ -15,6 +15,64 @@ class UserStore
// User Operations (Full User Object)
// =========================================================================
/**
* List all users for a tenant with optional filters
*/
public function listUsers(string $tenant, array $filters = []): array
{
// Build filter
$filter = ['tid' => $tenant];
if (isset($filters['enabled'])) {
$filter['enabled'] = (bool)$filters['enabled'];
}
if (isset($filters['role'])) {
$filter['roles'] = $filters['role'];
}
// Fetch users with aggregated role data
$pipeline = [
['$match' => $filter],
[
'$lookup' => [
'from' => 'user_roles',
'localField' => 'roles',
'foreignField' => 'rid',
'as' => 'role_details'
]
],
[
'$addFields' => [
'permissions' => [
'$reduce' => [
'input' => [
'$map' => [
'input' => '$role_details',
'as' => 'r',
'in' => ['$ifNull' => ['$$r.permissions', []]]
]
],
'initialValue' => [],
'in' => ['$setUnion' => ['$$value', '$$this']]
]
]
]
],
['$unset' => 'role_details'],
['$sort' => ['label' => 1]]
];
$cursor = $this->store->selectCollection('user_accounts')->aggregate($pipeline);
$users = [];
foreach ($cursor as $entry) {
$users[] = (array)$entry;
}
return $users;
}
public function fetchByIdentity(string $tenant, string $identity): array | null
{
@@ -55,7 +113,7 @@ class UserStore
[ '$unset' => 'role_details' ]
];
$entry = $this->store->selectCollection('users')->aggregate($pipeline)->toArray()[0] ?? null;
$entry = $this->store->selectCollection('user_accounts')->aggregate($pipeline)->toArray()[0] ?? null;
if (!$entry) { return null; }
return (array)$entry;
}
@@ -97,14 +155,14 @@ class UserStore
[ '$unset' => 'role_details' ]
];
$entry = $this->store->selectCollection('users')->aggregate($pipeline)->toArray()[0] ?? null;
$entry = $this->store->selectCollection('user_accounts')->aggregate($pipeline)->toArray()[0] ?? null;
if (!$entry) { return null; }
return (array)$entry;
}
public function fetchByProviderSubject(string $tenant, string $provider, string $subject): array | null
{
$entry = $this->store->selectCollection('users')->findOne([
$entry = $this->store->selectCollection('user_accounts')->findOne([
'tid' => $tenant,
'provider' => $provider,
'provider_subject' => $subject
@@ -122,14 +180,14 @@ class UserStore
$userData['profile'] = $userData['profile'] ?? [];
$userData['settings'] = $userData['settings'] ?? [];
$this->store->selectCollection('users')->insertOne($userData);
$this->store->selectCollection('user_accounts')->insertOne($userData);
return $this->fetchByIdentifier($tenant, $userData['uid']);
}
public function updateUser(string $tenant, string $uid, array $updates): bool
{
$result = $this->store->selectCollection('users')->updateOne(
$result = $this->store->selectCollection('user_accounts')->updateOne(
['tid' => $tenant, 'uid' => $uid],
['$set' => $updates]
);
@@ -139,7 +197,7 @@ class UserStore
public function deleteUser(string $tenant, string $uid): bool
{
$result = $this->store->selectCollection('users')->deleteOne([
$result = $this->store->selectCollection('user_accounts')->deleteOne([
'tid' => $tenant,
'uid' => $uid
]);
@@ -153,7 +211,7 @@ class UserStore
public function fetchProfile(string $tenant, string $uid): ?array
{
$user = $this->store->selectCollection('users')->findOne(
$user = $this->store->selectCollection('user_accounts')->findOne(
['tid' => $tenant, 'uid' => $uid],
['projection' => ['profile' => 1, 'provider_managed_fields' => 1]]
);
@@ -179,7 +237,7 @@ class UserStore
$updates["profile.{$key}"] = $value;
}
$result = $this->store->selectCollection('users')->updateOne(
$result = $this->store->selectCollection('user_accounts')->updateOne(
['tid' => $tenant, 'uid' => $uid],
['$set' => $updates]
);
@@ -194,7 +252,7 @@ class UserStore
public function fetchSettings(string $tenant, string $uid, array $settings = []): ?array
{
// Only fetch the settings field from the database
$user = $this->store->selectCollection('users')->findOne(
$user = $this->store->selectCollection('user_accounts')->findOne(
['tid' => $tenant, 'uid' => $uid],
['projection' => ['settings' => 1]]
);
@@ -227,7 +285,7 @@ class UserStore
$updates["settings.{$key}"] = $value;
}
$result = $this->store->selectCollection('users')->updateOne(
$result = $this->store->selectCollection('user_accounts')->updateOne(
['tid' => $tenant, 'uid' => $uid],
['$set' => $updates]
);

View File

@@ -0,0 +1,142 @@
<?php
namespace KTXC\Stores;
use KTXC\Db\DataStore;
use KTXC\Module\ModuleManager;
use KTXF\Utile\UUID;
/**
* Role Store - Database operations for user roles
*/
class UserRolesStore
{
protected const COLLECTION_NAME = 'user_roles';
public function __construct(
protected readonly DataStore $store,
protected readonly ModuleManager $moduleManager
) {}
// =========================================================================
// Role Operations
// =========================================================================
/**
* List all roles for a tenant
*/
public function listRoles(string $tenant): array
{
$cursor = $this->store->selectCollection(self::COLLECTION_NAME)->find(
['tid' => $tenant],
['sort' => ['label' => 1]]
);
$roles = [];
foreach ($cursor as $entry) {
$role = (array)$entry;
// Ensure permissions is an array
if (isset($role['permissions'])) {
$role['permissions'] = (array)$role['permissions'];
}
$roles[] = $role;
}
return $roles;
}
/**
* Fetch role by tenant and role ID
*/
public function fetchByRid(string $tenant, string $rid): ?array
{
$entry = $this->store->selectCollection(self::COLLECTION_NAME)->findOne([
'tid' => $tenant,
'rid' => $rid
]);
if (!$entry) {
return null;
}
return (array)$entry;
}
/**
* Create a new role
*/
public function createRole(string $tenant, array $roleData): array
{
$roleData['tid'] = $tenant;
$roleData['rid'] = $roleData['rid'] ?? UUID::v4();
$roleData['label'] = $roleData['label'] ?? 'Unnamed Role';
$roleData['description'] = $roleData['description'] ?? '';
$roleData['permissions'] = $roleData['permissions'] ?? [];
$roleData['system'] = $roleData['system'] ?? false;
$this->store->selectCollection(self::COLLECTION_NAME)->insertOne($roleData);
return $this->fetchByRid($tenant, $roleData['rid']);
}
/**
* Update an existing role
*/
public function updateRole(string $tenant, string $rid, array $updates): bool
{
// Prevent updating system flag
unset($updates['tid'], $updates['rid'], $updates['system']);
if (empty($updates)) {
return false;
}
$result = $this->store->selectCollection(self::COLLECTION_NAME)->updateOne(
['tid' => $tenant, 'rid' => $rid],
['$set' => $updates]
);
return $result->getModifiedCount() > 0;
}
/**
* Delete a role
*/
public function deleteRole(string $tenant, string $rid): bool
{
// Check if role is system role
$role = $this->fetchByRid($tenant, $rid);
if (!$role || ($role['system'] ?? false)) {
return false; // Cannot delete system roles
}
$result = $this->store->selectCollection(self::COLLECTION_NAME)->deleteOne([
'tid' => $tenant,
'rid' => $rid
]);
return $result->getDeletedCount() > 0;
}
/**
* Count users assigned to a role
*/
public function countUsersInRole(string $tenant, string $rid): int
{
$count = $this->store->selectCollection('user_accounts')->countDocuments([
'tid' => $tenant,
'roles' => $rid
]);
return (int)$count;
}
/**
* Get all available permissions from modules
* Grouped by category with metadata
*/
public function availablePermissions(): array
{
return $this->moduleManager->availablePermissions();
}
}