146 lines
4.9 KiB
PHP
146 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\BackupItem;
|
|
use App\Models\Tenant;
|
|
use App\Services\Graph\AssignmentFetcher;
|
|
use App\Services\Graph\GroupResolver;
|
|
use App\Services\Graph\ScopeTagResolver;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class AssignmentBackupService
|
|
{
|
|
public function __construct(
|
|
private readonly AssignmentFetcher $assignmentFetcher,
|
|
private readonly GroupResolver $groupResolver,
|
|
private readonly ScopeTagResolver $scopeTagResolver,
|
|
) {}
|
|
|
|
/**
|
|
* Enrich a backup item with assignments and scope tag metadata.
|
|
*
|
|
* @param BackupItem $backupItem The backup item to enrich
|
|
* @param Tenant $tenant Tenant model with credentials
|
|
* @param string $policyId Policy ID (external_id from Graph)
|
|
* @param array $policyPayload Full policy payload from Graph
|
|
* @param bool $includeAssignments Whether to fetch and include assignments
|
|
* @return BackupItem Updated backup item with assignments and metadata
|
|
*/
|
|
public function enrichWithAssignments(
|
|
BackupItem $backupItem,
|
|
Tenant $tenant,
|
|
string $policyId,
|
|
array $policyPayload,
|
|
bool $includeAssignments = false
|
|
): BackupItem {
|
|
// Extract scope tags from payload (always available in policy)
|
|
$scopeTagIds = $policyPayload['roleScopeTagIds'] ?? ['0'];
|
|
$scopeTagNames = $this->resolveScopeTagNames($scopeTagIds, $tenant);
|
|
|
|
$metadata = $backupItem->metadata ?? [];
|
|
$metadata['scope_tag_ids'] = $scopeTagIds;
|
|
$metadata['scope_tag_names'] = $scopeTagNames;
|
|
|
|
// Only fetch assignments if explicitly requested
|
|
if (! $includeAssignments) {
|
|
$metadata['assignment_count'] = 0;
|
|
$backupItem->update([
|
|
'assignments' => null,
|
|
'metadata' => $metadata,
|
|
]);
|
|
|
|
return $backupItem->refresh();
|
|
}
|
|
|
|
// Fetch assignments from Graph API
|
|
$graphOptions = $tenant->graphOptions();
|
|
$tenantId = $graphOptions['tenant'] ?? $tenant->external_id ?? $tenant->tenant_id;
|
|
$assignments = $this->assignmentFetcher->fetch($tenantId, $policyId, $graphOptions);
|
|
|
|
if (empty($assignments)) {
|
|
// No assignments or fetch failed
|
|
$metadata['assignment_count'] = 0;
|
|
$metadata['assignments_fetch_failed'] = true;
|
|
$metadata['has_orphaned_assignments'] = false;
|
|
|
|
$backupItem->update([
|
|
'assignments' => [], // Return empty array instead of null
|
|
'metadata' => $metadata,
|
|
]);
|
|
|
|
Log::warning('No assignments fetched for policy', [
|
|
'tenant_id' => $tenantId,
|
|
'policy_id' => $policyId,
|
|
'backup_item_id' => $backupItem->id,
|
|
]);
|
|
|
|
return $backupItem->refresh();
|
|
}
|
|
|
|
// Extract group IDs and resolve for orphan detection
|
|
$groupIds = $this->extractGroupIds($assignments);
|
|
$hasOrphanedGroups = false;
|
|
|
|
if (! empty($groupIds)) {
|
|
$resolvedGroups = $this->groupResolver->resolveGroupIds($groupIds, $tenantId, $graphOptions);
|
|
$hasOrphanedGroups = collect($resolvedGroups)->contains('orphaned', true);
|
|
}
|
|
|
|
// Update backup item with assignments and metadata
|
|
$metadata['assignment_count'] = count($assignments);
|
|
$metadata['assignments_fetch_failed'] = false;
|
|
$metadata['has_orphaned_assignments'] = $hasOrphanedGroups;
|
|
|
|
$backupItem->update([
|
|
'assignments' => $assignments,
|
|
'metadata' => $metadata,
|
|
]);
|
|
|
|
Log::info('Assignments enriched for backup item', [
|
|
'tenant_id' => $tenantId,
|
|
'policy_id' => $policyId,
|
|
'backup_item_id' => $backupItem->id,
|
|
'assignment_count' => count($assignments),
|
|
'has_orphaned' => $hasOrphanedGroups,
|
|
]);
|
|
|
|
return $backupItem->refresh();
|
|
}
|
|
|
|
/**
|
|
* Resolve scope tag IDs to display names.
|
|
*/
|
|
private function resolveScopeTagNames(array $scopeTagIds, Tenant $tenant): array
|
|
{
|
|
$scopeTags = $this->scopeTagResolver->resolve($scopeTagIds, $tenant);
|
|
|
|
$names = [];
|
|
foreach ($scopeTagIds as $id) {
|
|
$scopeTag = collect($scopeTags)->firstWhere('id', $id);
|
|
$names[] = $scopeTag['displayName'] ?? "Unknown (ID: {$id})";
|
|
}
|
|
|
|
return $names;
|
|
}
|
|
|
|
/**
|
|
* Extract group IDs from assignment array.
|
|
*/
|
|
private function extractGroupIds(array $assignments): array
|
|
{
|
|
$groupIds = [];
|
|
|
|
foreach ($assignments as $assignment) {
|
|
$target = $assignment['target'] ?? [];
|
|
$odataType = $target['@odata.type'] ?? '';
|
|
|
|
if ($odataType === '#microsoft.graph.groupAssignmentTarget' && isset($target['groupId'])) {
|
|
$groupIds[] = $target['groupId'];
|
|
}
|
|
}
|
|
|
|
return array_unique($groupIds);
|
|
}
|
|
}
|