feat: complete jobcard client management foundation

This commit is contained in:
Marco0300
2026-09-01 20:43:24 +02:00
parent 168c15c6ae
commit de2bf277c4
34 changed files with 2072 additions and 74 deletions
+68
View File
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../app/Domain/Attachment/AttachmentValidator.php';
require_once __DIR__ . '/../app/Domain/Notification/NotificationRecord.php';
use App\Domain\Attachment\AttachmentValidator;
use App\Domain\Notification\NotificationRecord;
function attachment_notification_assert_same(mixed $expected, mixed $actual, string $message): void
{
if ($expected !== $actual) {
throw new RuntimeException($message . "\nExpected: " . var_export($expected, true) . "\nActual: " . var_export($actual, true));
}
}
$attachments = new AttachmentValidator(5_000_000);
$validAttachment = $attachments->validate([
'name' => ' Site Photo.JPG ',
'mime_type' => 'IMAGE/JPEG',
'size' => '2048',
'client_visible' => 'yes',
'client_approved' => 'true',
]);
attachment_notification_assert_same(true, $validAttachment['valid'], 'A safe approved image attachment should validate.');
attachment_notification_assert_same('Site Photo.JPG', $validAttachment['name'], 'Attachment names should be trimmed without changing case.');
attachment_notification_assert_same('jpg', $validAttachment['extension'], 'Attachment extensions should normalize to lowercase.');
attachment_notification_assert_same('image/jpeg', $validAttachment['mime_type'], 'Attachment MIME types should normalize to lowercase.');
attachment_notification_assert_same(2048, $validAttachment['size_bytes'], 'Attachment sizes should normalize to bytes.');
attachment_notification_assert_same(true, $validAttachment['client_visible'], 'Client visibility should normalize to boolean.');
foreach ([
['name' => '../secret.pdf', 'mime_type' => 'application/pdf', 'size_bytes' => 10],
['name' => 'invoice.php.jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10],
['name' => 'photo.jpg', 'mime_type' => 'application/x-php', 'size_bytes' => 10],
['name' => 'photo.jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 5_000_001],
['name' => 'photo.jpg', 'mime_type' => 'image/jpeg', 'size_bytes' => 10, 'client_visible' => true, 'client_approved' => false],
] as $invalidPayload) {
attachment_notification_assert_same(false, $attachments->validate($invalidPayload)['valid'], 'Unsafe attachment metadata should be rejected.');
}
$notifications = new NotificationRecord();
$notification = $notifications->validate([
'type' => ' JOBCARD_STATUS_CHANGED ',
'recipients' => [' Support@Example.com ', 'support@example.com', 'client@example.com'],
'is_read' => '0',
'deduplication_key' => ' Jobcard:42:Status:closed ',
]);
attachment_notification_assert_same(true, $notification['valid'], 'A valid notification should validate.');
attachment_notification_assert_same('jobcard_status_changed', $notification['type'], 'Notification types should normalize to lowercase snake case.');
attachment_notification_assert_same(['support@example.com', 'client@example.com'], $notification['recipients'], 'Recipients should normalize, lowercase and de-duplicate.');
attachment_notification_assert_same(false, $notification['is_read'], 'Unread notification state should normalize to false.');
attachment_notification_assert_same('jobcard:42:status:closed', $notification['deduplication_key'], 'Deduplication keys should normalize case and whitespace.');
$invalidNotification = $notifications->validate([
'type' => 'unknown-event',
'recipients' => ['not-an-email'],
'is_read' => 'maybe',
'deduplication_key' => '',
]);
attachment_notification_assert_same(false, $invalidNotification['valid'], 'Invalid notification metadata should be rejected.');
foreach (['type', 'recipients', 'is_read', 'deduplication_key'] as $field) {
if (!isset($invalidNotification['errors'][$field])) {
throw new RuntimeException("Expected validation error for {$field}.");
}
}
printf("Attachment and notification tests: 7 passed\n");