authentication provider provisioning
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
namespace KTXC\Stores;
|
||||
|
||||
use KTXC\Db\DataStore;
|
||||
use KTXC\Db\Collection;
|
||||
use KTXF\Utile\UUID;
|
||||
|
||||
class UserStore
|
||||
{
|
||||
@@ -11,6 +11,10 @@ class UserStore
|
||||
public function __construct(protected DataStore $store)
|
||||
{ }
|
||||
|
||||
// =========================================================================
|
||||
// User Operations (Full User Object)
|
||||
// =========================================================================
|
||||
|
||||
public function fetchByIdentity(string $tenant, string $identity): array | null
|
||||
{
|
||||
|
||||
@@ -63,195 +67,137 @@ class UserStore
|
||||
return (array)$entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch user settings from the embedded settings field in the user document
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @param array $settings Optional array of specific setting keys to retrieve
|
||||
* @return array|null Settings array or null if user not found
|
||||
*/
|
||||
public function fetchSettings(string $tenant, string $identifier, array $keys = []): array | null
|
||||
{
|
||||
$entry = $this->store->selectCollection('users')->findOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['projection' => ['settings' => 1]]
|
||||
);
|
||||
|
||||
if (!$entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$settings = (array)($entry['settings'] ?? []);
|
||||
|
||||
if (empty($keys)) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
// Filter to only requested keys
|
||||
return array_filter(
|
||||
$settings,
|
||||
fn($key) => in_array($key, $keys),
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store/update user settings in the embedded settings field
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @param array $settings Key-value pairs to set/update
|
||||
* @return bool Whether the update was acknowledged
|
||||
*/
|
||||
public function storeSettings(string $tenant, string $identifier, array $settings): bool
|
||||
{
|
||||
// Build dot-notation update for each setting key
|
||||
$setFields = [];
|
||||
foreach ($settings as $key => $value) {
|
||||
$setFields["settings.$key"] = $value;
|
||||
}
|
||||
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['$set' => $setFields]
|
||||
);
|
||||
|
||||
return $result->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove specific settings from a user
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @param array $keys Setting keys to remove
|
||||
* @return bool Whether the update was acknowledged
|
||||
*/
|
||||
public function removeSettings(string $tenant, string $identifier, array $keys): bool
|
||||
{
|
||||
$unsetFields = [];
|
||||
foreach ($keys as $key) {
|
||||
$unsetFields["settings.$key"] = "";
|
||||
}
|
||||
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['$unset' => $unsetFields]
|
||||
);
|
||||
|
||||
return $result->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user
|
||||
*
|
||||
* @param array $data User data including tid, uid, identity, label, provider, etc.
|
||||
* @return string|null The created user's UID or null on failure
|
||||
*/
|
||||
public function create(array $data): ?string
|
||||
{
|
||||
// Ensure required fields
|
||||
if (empty($data['tid']) || empty($data['uid']) || empty($data['identity'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set defaults
|
||||
$data['enabled'] = $data['enabled'] ?? true;
|
||||
$data['roles'] = $data['roles'] ?? [];
|
||||
$data['profile'] = $data['profile'] ?? [];
|
||||
$data['settings'] = $data['settings'] ?? [];
|
||||
$data['initial_login'] = $data['initial_login'] ?? time();
|
||||
$data['recent_login'] = $data['recent_login'] ?? time();
|
||||
|
||||
$result = $this->store->selectCollection('users')->insertOne($data);
|
||||
|
||||
if ($result->isAcknowledged()) {
|
||||
return $data['uid'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user profile fields
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @param array $profile Profile data to update
|
||||
* @return bool Whether the update was acknowledged
|
||||
*/
|
||||
public function updateProfile(string $tenant, string $identifier, array $profile): bool
|
||||
{
|
||||
$setFields = [];
|
||||
foreach ($profile as $key => $value) {
|
||||
$setFields["profile.$key"] = $value;
|
||||
}
|
||||
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['$set' => $setFields]
|
||||
);
|
||||
|
||||
return $result->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's last login timestamp
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @return bool Whether the update was acknowledged
|
||||
*/
|
||||
public function updateLastLogin(string $tenant, string $identifier): bool
|
||||
{
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['$set' => ['recent_login' => time()]]
|
||||
);
|
||||
|
||||
return $result->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's label
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $identifier User identifier
|
||||
* @param string $label New label
|
||||
* @return bool Whether the update was acknowledged
|
||||
*/
|
||||
public function updateLabel(string $tenant, string $identifier, string $label): bool
|
||||
{
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $identifier],
|
||||
['$set' => ['label' => $label]]
|
||||
);
|
||||
|
||||
return $result->isAcknowledged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find user by external subject (for external identity providers)
|
||||
*
|
||||
* @param string $tenant Tenant identifier
|
||||
* @param string $provider Provider identifier
|
||||
* @param string $externalSubject External subject identifier
|
||||
* @return array|null User data or null if not found
|
||||
*/
|
||||
public function fetchByExternalSubject(string $tenant, string $provider, string $externalSubject): ?array
|
||||
public function fetchByProviderSubject(string $tenant, string $provider, string $subject): array | null
|
||||
{
|
||||
$entry = $this->store->selectCollection('users')->findOne([
|
||||
'tid' => $tenant,
|
||||
'provider' => $provider,
|
||||
'external_subject' => $externalSubject
|
||||
'provider_subject' => $subject
|
||||
]);
|
||||
|
||||
if (!$entry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$entry) { return null; }
|
||||
return (array)$entry;
|
||||
}
|
||||
|
||||
public function createUser(string $tenant, array $userData): array
|
||||
{
|
||||
$userData['tid'] = $tenant;
|
||||
$userData['uid'] = $userData['uid'] ?? UUID::v4();
|
||||
$userData['enabled'] = $userData['enabled'] ?? true;
|
||||
$userData['roles'] = $userData['roles'] ?? [];
|
||||
$userData['profile'] = $userData['profile'] ?? [];
|
||||
$userData['settings'] = $userData['settings'] ?? [];
|
||||
|
||||
$this->store->selectCollection('users')->insertOne($userData);
|
||||
|
||||
return $this->fetchByIdentifier($tenant, $userData['uid']);
|
||||
}
|
||||
|
||||
public function updateUser(string $tenant, string $uid, array $updates): bool
|
||||
{
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $uid],
|
||||
['$set' => $updates]
|
||||
);
|
||||
|
||||
return $result->getModifiedCount() > 0;
|
||||
}
|
||||
|
||||
public function deleteUser(string $tenant, string $uid): bool
|
||||
{
|
||||
$result = $this->store->selectCollection('users')->deleteOne([
|
||||
'tid' => $tenant,
|
||||
'uid' => $uid
|
||||
]);
|
||||
|
||||
return $result->getDeletedCount() > 0;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Profile Operations
|
||||
// =========================================================================
|
||||
|
||||
public function fetchProfile(string $tenant, string $uid): ?array
|
||||
{
|
||||
$user = $this->store->selectCollection('users')->findOne(
|
||||
['tid' => $tenant, 'uid' => $uid],
|
||||
['projection' => ['profile' => 1, 'provider_managed_fields' => 1]]
|
||||
);
|
||||
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'profile' => $user['profile'] ?? [],
|
||||
'provider_managed_fields' => $user['provider_managed_fields'] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
public function storeProfile(string $tenant, string $uid, array $profileFields): bool
|
||||
{
|
||||
if (empty($profileFields)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
foreach ($profileFields as $key => $value) {
|
||||
$updates["profile.{$key}"] = $value;
|
||||
}
|
||||
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $uid],
|
||||
['$set' => $updates]
|
||||
);
|
||||
|
||||
return $result->getModifiedCount() > 0;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Settings Operations
|
||||
// =========================================================================
|
||||
|
||||
public function fetchSettings(string $tenant, string $uid, array $settings = []): ?array
|
||||
{
|
||||
// Only fetch the settings field from the database
|
||||
$user = $this->store->selectCollection('users')->findOne(
|
||||
['tid' => $tenant, 'uid' => $uid],
|
||||
['projection' => ['settings' => 1]]
|
||||
);
|
||||
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$userSettings = $user['settings'] ?? [];
|
||||
|
||||
if (empty($settings)) {
|
||||
return $userSettings;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($settings as $key) {
|
||||
$result[$key] = $userSettings[$key] ?? null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function storeSettings(string $tenant, string $uid, array $settings): bool
|
||||
{
|
||||
if (empty($settings)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updates = [];
|
||||
foreach ($settings as $key => $value) {
|
||||
$updates["settings.{$key}"] = $value;
|
||||
}
|
||||
|
||||
$result = $this->store->selectCollection('users')->updateOne(
|
||||
['tid' => $tenant, 'uid' => $uid],
|
||||
['$set' => $updates]
|
||||
);
|
||||
|
||||
return $result->getModifiedCount() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user