TenantAtlas/app/Services/Intune/TermsAndConditionsNormalizer.php
ahmido 83f1814254 feat/024-terms-and-conditions (#30)
Added termsAndConditions to the supported policy list and Graph contract so Intune sync/backup/restore paths (and scope tag handling) treat Terms & Conditions like other enrollment policies, ensuring listings, snapshots, assignments CRUD, and restore modes flow naturally (tenantpilot.php (lines 168-225), graph_contracts.php (lines 520-560), InteractsWithODataTypes.php (lines 10-30)).
Exposed a dedicated TermsAndConditionsNormalizer and tagged it in AppServiceProvider so the Filament UI shows readable rows (display name, title, acceptance statement, body, scope tags) and the diff engine flattens them consistently (TermsAndConditionsNormalizer.php (lines 1-94), AppServiceProvider.php (lines 43-58)).
Added Pest coverage for the new type that checks config/contract entries, assignment restore behavior, normalized output, and PolicySync ingestion (TermsAndConditionsPolicyTypeTest.php (lines 70-200)).
Tests:

TermsAndConditionsPolicyTypeTest.php
./vendor/bin/pint --dirty

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #30
2026-01-04 03:01:11 +00:00

95 lines
2.8 KiB
PHP

<?php
namespace App\Services\Intune;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class TermsAndConditionsNormalizer implements PolicyTypeNormalizer
{
public function __construct(
private readonly DefaultPolicyNormalizer $defaultNormalizer,
) {}
public function supports(string $policyType): bool
{
return $policyType === 'termsAndConditions';
}
/**
* @return array{status: string, settings: array<int, array<string, mixed>>, warnings: array<int, string>}
*/
public function normalize(?array $snapshot, string $policyType, ?string $platform = null): array
{
$snapshot = is_array($snapshot) ? $snapshot : [];
$entries = [];
$this->pushEntry($entries, 'Display name', Arr::get($snapshot, 'displayName'));
$this->pushEntry($entries, 'Title', Arr::get($snapshot, 'title'));
$this->pushEntry($entries, 'Description', Arr::get($snapshot, 'description'));
$this->pushEntry($entries, 'Acceptance statement', Arr::get($snapshot, 'acceptanceStatement'));
$this->pushEntry($entries, 'Body text', $this->limitText(Arr::get($snapshot, 'bodyText')));
$this->pushEntry($entries, 'Version', Arr::get($snapshot, 'version'));
$roleScopeTagIds = Arr::get($snapshot, 'roleScopeTagIds');
if (is_array($roleScopeTagIds) && $roleScopeTagIds !== []) {
$this->pushEntry($entries, 'Scope tag IDs', array_values($roleScopeTagIds));
}
if ($entries === []) {
return [
'status' => 'warning',
'settings' => [],
'warnings' => ['Terms & Conditions snapshot contains no readable fields.'],
];
}
return [
'status' => 'ok',
'settings' => [
[
'type' => 'keyValue',
'title' => 'Terms & Conditions',
'entries' => $entries,
],
],
'warnings' => [],
];
}
public function flattenForDiff(?array $snapshot, string $policyType, ?string $platform = null): array
{
$normalized = $this->normalize($snapshot ?? [], $policyType, $platform);
return $this->defaultNormalizer->flattenNormalizedForDiff($normalized);
}
/**
* @param array<int, array<string, mixed>> $entries
*/
private function pushEntry(array &$entries, string $key, mixed $value): void
{
if ($value === null) {
return;
}
if (is_string($value) && $value === '') {
return;
}
$entries[] = [
'key' => $key,
'value' => $value,
];
}
private function limitText(mixed $value): mixed
{
if (! is_string($value)) {
return $value;
}
return Str::limit($value, 1000);
}
}