chore: snapshot notifications hardening and css/docs alignment
This commit is contained in:
@@ -103,10 +103,8 @@ class UserAccountService
|
||||
}
|
||||
|
||||
// Capture tenant associations before CASCADE deletes them
|
||||
$preDeletionTenantIds = array_column(
|
||||
$this->userAssignmentService->buildAssignmentsForUser($userId)['tenants'] ?? [],
|
||||
'id'
|
||||
);
|
||||
$preDeletionAssignments = $this->safeAssignmentsForUser($userId);
|
||||
$preDeletionTenantIds = $this->extractTenantIdsFromAssignments($preDeletionAssignments);
|
||||
|
||||
$deleted = $this->userWriteRepository->delete($userId);
|
||||
if (!$deleted) {
|
||||
@@ -156,6 +154,27 @@ class UserAccountService
|
||||
}
|
||||
}
|
||||
|
||||
$deletedUsers = [];
|
||||
foreach ($uuids as $deleteUuid) {
|
||||
$user = $this->userReadRepository->findByUuid((string) $deleteUuid);
|
||||
if (!$user || !isset($user['id'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$deleteUserId = (int) $user['id'];
|
||||
if ($deleteUserId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assignments = $this->safeAssignmentsForUser($deleteUserId);
|
||||
$deletedUsers[] = [
|
||||
'id' => $deleteUserId,
|
||||
'uuid' => (string) ($user['uuid'] ?? ''),
|
||||
'display_name' => trim((string) ($user['display_name'] ?? '')),
|
||||
'tenant_ids' => $this->extractTenantIdsFromAssignments($assignments),
|
||||
];
|
||||
}
|
||||
|
||||
$deleted = $this->userWriteRepository->deleteByUuids($uuids);
|
||||
if (!$deleted) {
|
||||
return ['ok' => false, 'error' => 'delete_failed'];
|
||||
@@ -171,6 +190,16 @@ class UserAccountService
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($deletedUsers as $deletedUser) {
|
||||
$this->eventDispatcher?->dispatch('user.deleted', [
|
||||
'user_id' => (int) ($deletedUser['id'] ?? 0),
|
||||
'uuid' => (string) ($deletedUser['uuid'] ?? ''),
|
||||
'actor_user_id' => $currentUserId,
|
||||
'display_name' => (string) ($deletedUser['display_name'] ?? ''),
|
||||
'tenant_ids' => is_array($deletedUser['tenant_ids'] ?? null) ? $deletedUser['tenant_ids'] : [],
|
||||
]);
|
||||
}
|
||||
|
||||
return ['ok' => true, 'count' => count($uuids)];
|
||||
}
|
||||
|
||||
@@ -434,6 +463,20 @@ class UserAccountService
|
||||
],
|
||||
]);
|
||||
|
||||
if ($activeChanged) {
|
||||
$tenantIds = $this->extractTenantIdsFromAssignments(
|
||||
$this->safeAssignmentsForUser($userId)
|
||||
);
|
||||
$eventType = ((int) $form['active'] === 1) ? 'user.activated' : 'user.deactivated';
|
||||
$this->eventDispatcher?->dispatch($eventType, [
|
||||
'user_id' => $userId,
|
||||
'uuid' => (string) ($existing['uuid'] ?? ''),
|
||||
'display_name' => trim((string) ($existing['display_name'] ?? '')),
|
||||
'actor_user_id' => $currentUserId,
|
||||
'tenant_ids' => $tenantIds,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['ok' => true, 'form' => $form];
|
||||
}
|
||||
|
||||
@@ -475,6 +518,17 @@ class UserAccountService
|
||||
'after' => ['active' => $active ? 1 : 0],
|
||||
]);
|
||||
|
||||
$tenantIds = $this->extractTenantIdsFromAssignments(
|
||||
$this->safeAssignmentsForUser($userId)
|
||||
);
|
||||
$this->eventDispatcher?->dispatch($active ? 'user.activated' : 'user.deactivated', [
|
||||
'user_id' => $userId,
|
||||
'uuid' => (string) ($user['uuid'] ?? ''),
|
||||
'display_name' => trim((string) ($user['display_name'] ?? '')),
|
||||
'actor_user_id' => $currentUserId,
|
||||
'tenant_ids' => $tenantIds,
|
||||
]);
|
||||
|
||||
return ['ok' => true, 'user' => $user];
|
||||
}
|
||||
|
||||
@@ -519,6 +573,29 @@ class UserAccountService
|
||||
],
|
||||
]);
|
||||
|
||||
foreach ($uuids as $uuid) {
|
||||
$user = $this->userReadRepository->findByUuid((string) $uuid);
|
||||
if (!$user || !isset($user['id'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$targetUserId = (int) ($user['id'] ?? 0);
|
||||
if ($targetUserId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tenantIds = $this->extractTenantIdsFromAssignments(
|
||||
$this->safeAssignmentsForUser($targetUserId)
|
||||
);
|
||||
$this->eventDispatcher?->dispatch($active ? 'user.activated' : 'user.deactivated', [
|
||||
'user_id' => $targetUserId,
|
||||
'uuid' => (string) ($user['uuid'] ?? ''),
|
||||
'display_name' => trim((string) ($user['display_name'] ?? '')),
|
||||
'actor_user_id' => $currentUserId,
|
||||
'tenant_ids' => $tenantIds,
|
||||
]);
|
||||
}
|
||||
|
||||
return ['ok' => true, 'count' => count($uuids)];
|
||||
}
|
||||
|
||||
@@ -695,6 +772,49 @@ class UserAccountService
|
||||
return ['ok' => true, 'form' => $form];
|
||||
}
|
||||
|
||||
public function dispatchAssignmentChangedIfNeeded(
|
||||
int $userId,
|
||||
array $beforeAssignments,
|
||||
array $afterAssignments,
|
||||
int $currentUserId = 0
|
||||
): void {
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$beforeTenantIds = $this->extractTenantIdsFromAssignments($beforeAssignments);
|
||||
$afterTenantIds = $this->extractTenantIdsFromAssignments($afterAssignments);
|
||||
$beforeRoleIds = $this->extractAssignmentIds($beforeAssignments, 'roles');
|
||||
$afterRoleIds = $this->extractAssignmentIds($afterAssignments, 'roles');
|
||||
$beforeDepartmentIds = $this->extractAssignmentIds($beforeAssignments, 'departments');
|
||||
$afterDepartmentIds = $this->extractAssignmentIds($afterAssignments, 'departments');
|
||||
|
||||
$tenantsChanged = $beforeTenantIds !== $afterTenantIds;
|
||||
$rolesChanged = $beforeRoleIds !== $afterRoleIds;
|
||||
$departmentsChanged = $beforeDepartmentIds !== $afterDepartmentIds;
|
||||
if (!$tenantsChanged && !$rolesChanged && !$departmentsChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->userReadRepository->find($userId);
|
||||
if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->eventDispatcher?->dispatch('user.assignment_changed', [
|
||||
'user_id' => $userId,
|
||||
'uuid' => (string) ($user['uuid'] ?? ''),
|
||||
'display_name' => trim((string) ($user['display_name'] ?? '')),
|
||||
'actor_user_id' => $currentUserId,
|
||||
'tenant_ids' => array_values(array_unique(array_merge($beforeTenantIds, $afterTenantIds))),
|
||||
'changes' => [
|
||||
'tenants' => ['before' => $beforeTenantIds, 'after' => $afterTenantIds],
|
||||
'roles' => ['before' => $beforeRoleIds, 'after' => $afterRoleIds],
|
||||
'departments' => ['before' => $beforeDepartmentIds, 'after' => $afterDepartmentIds],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
private function filterUuidsByTenantScope(array $uuids, int $currentUserId): array
|
||||
{
|
||||
$allowed = [];
|
||||
@@ -715,6 +835,37 @@ class UserAccountService
|
||||
return array_values(array_unique($allowed));
|
||||
}
|
||||
|
||||
private function extractTenantIdsFromAssignments(array $assignments): array
|
||||
{
|
||||
return $this->extractAssignmentIds($assignments, 'tenants');
|
||||
}
|
||||
|
||||
private function safeAssignmentsForUser(int $userId): array
|
||||
{
|
||||
$assignments = $this->userAssignmentService->buildAssignmentsForUser($userId);
|
||||
return is_array($assignments) ? $assignments : [];
|
||||
}
|
||||
|
||||
private function extractAssignmentIds(array $assignments, string $key): array
|
||||
{
|
||||
$rows = is_array($assignments[$key] ?? null) ? $assignments[$key] : [];
|
||||
$ids = [];
|
||||
foreach ($rows as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$id = (int) ($row['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$ids = array_values(array_unique($ids));
|
||||
sort($ids);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
private function sanitizeBase(array $input): array
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user