TenantAtlas/app/Services/Intune/ManagedDeviceAppConfigurationNormalizer.php
ahmido 412dd7ad66 feat/017-policy-types-mam-endpoint-security-baselines (#23)
Hydrate configurationPolicies/{id}/settings for endpoint security/baseline policies so snapshots include real rule data.
Treat those types like Settings Catalog policies in the normalizer so they show the searchable settings table, recognizable categories, and readable choice values (firewall-specific formatting + interface badge parsing).
Improve “General” tab cards: badge lists for platforms/technologies, template reference summary (name/family/version/ID), and ISO timestamps rendered as YYYY‑MM‑DD HH:MM:SS; added regression test for the view.

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #23
2026-01-03 02:06:35 +00:00

144 lines
4.5 KiB
PHP

<?php
namespace App\Services\Intune;
use Illuminate\Support\Str;
class ManagedDeviceAppConfigurationNormalizer implements PolicyTypeNormalizer
{
public function __construct(
private readonly DefaultPolicyNormalizer $defaultNormalizer,
) {}
public function supports(string $policyType): bool
{
return $policyType === 'managedDeviceAppConfiguration';
}
/**
* @return array{status: string, settings: array<int, array<string, mixed>>, settings_table?: array<string, mixed>, warnings: array<int, string>}
*/
public function normalize(?array $snapshot, string $policyType, ?string $platform = null): array
{
$snapshot = $snapshot ?? [];
$normalized = $this->defaultNormalizer->normalize($snapshot, $policyType, $platform);
if ($snapshot === []) {
return $normalized;
}
$normalized['settings'] = array_values(array_filter(
$normalized['settings'],
static function (array $block): bool {
$title = strtolower((string) ($block['title'] ?? ''));
return $title !== 'settings' && $title !== 'settings delta';
}
));
$rows = $this->buildSettingsRows($snapshot['settings'] ?? null);
if ($rows !== []) {
$normalized['settings'][] = [
'type' => 'table',
'title' => 'App configuration settings',
'rows' => $rows,
];
} else {
$normalized['warnings'][] = 'No app configuration settings were returned by Graph. Intune only returns configured keys; items shown as "Not configured" in the portal are typically absent.';
$normalized['warnings'] = array_values(array_unique(array_filter($normalized['warnings'], static fn ($value) => is_string($value) && $value !== '')));
}
return $normalized;
}
/**
* @return array<string, mixed>
*/
public function flattenForDiff(?array $snapshot, string $policyType, ?string $platform = null): array
{
$snapshot = $snapshot ?? [];
$normalized = $this->normalize($snapshot, $policyType, $platform);
return $this->defaultNormalizer->flattenNormalizedForDiff($normalized);
}
/**
* @return array<int, array<string, mixed>>
*/
private function buildSettingsRows(mixed $settings): array
{
if (! is_array($settings) || $settings === []) {
return [];
}
$rows = [];
foreach ($settings as $setting) {
if (! is_array($setting)) {
continue;
}
$key = $setting['appConfigKey'] ?? null;
$rawValue = $setting['appConfigKeyValue'] ?? null;
$type = $setting['appConfigKeyType'] ?? null;
if (! is_string($key) || $key === '') {
continue;
}
$value = $this->normalizeValue($rawValue, $type);
$rows[] = [
'path' => $key,
'label' => $key,
'value' => is_scalar($value) || $value === null ? $value : json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'description' => is_string($type) && $type !== '' ? Str::headline($type) : null,
];
}
return $rows;
}
private function normalizeValue(mixed $value, mixed $type): mixed
{
$type = is_string($type) ? strtolower($type) : '';
if (is_bool($value)) {
return $value;
}
if (is_int($value) || is_float($value)) {
return $value;
}
if (is_string($value)) {
$trimmed = trim($value);
if ($type !== '' && str_contains($type, 'boolean')) {
if (in_array(strtolower($trimmed), ['true', 'false'], true)) {
return strtolower($trimmed) === 'true';
}
if (in_array(strtolower($trimmed), ['yes', 'no'], true)) {
return strtolower($trimmed) === 'yes';
}
if (in_array($trimmed, ['1', '0'], true)) {
return $trimmed === '1';
}
}
if ($type !== '' && (str_contains($type, 'integer') || str_contains($type, 'int'))) {
if (is_numeric($trimmed) && (string) (int) $trimmed === $trimmed) {
return (int) $trimmed;
}
}
return $trimmed;
}
return $value;
}
}