added user and roles controllers and unified naming
This commit is contained in:
@@ -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]
|
||||
);
|
||||
142
core/lib/Stores/UserRolesStore.php
Normal file
142
core/lib/Stores/UserRolesStore.php
Normal 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user