177 lines
7.3 KiB
PHP
177 lines
7.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Site;
|
|
|
|
use App\Site\UI\Http\SiteController;
|
|
use Netig\Netslim\AuditLog\Contracts\AuditEntryView;
|
|
use Netig\Netslim\AuditLog\Contracts\AuditLoggerInterface;
|
|
use Netig\Netslim\AuditLog\Contracts\AuditLogReaderInterface;
|
|
use Netig\Netslim\Identity\Application\AuthorizationServiceInterface;
|
|
use Netig\Netslim\Identity\Domain\Policy\Permission;
|
|
use Netig\Netslim\Kernel\Http\Application\Flash\FlashServiceInterface;
|
|
use Netig\Netslim\Kernel\Http\Application\Session\SessionManagerInterface;
|
|
use Netig\Netslim\Notifications\Application\NotificationServiceInterface;
|
|
use Netig\Netslim\Notifications\Contracts\NotificationDispatchView;
|
|
use Netig\Netslim\Settings\Application\SettingsServiceInterface;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Tests\ControllerTestBase;
|
|
|
|
#[\PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations]
|
|
final class SiteControllerTest extends ControllerTestBase
|
|
{
|
|
private \Slim\Views\Twig $view;
|
|
|
|
private MockObject&SettingsServiceInterface $settings;
|
|
|
|
private AuditLoggerInterface&MockObject $auditLogger;
|
|
|
|
private AuditLogReaderInterface&MockObject $auditLogReader;
|
|
|
|
private MockObject&NotificationServiceInterface $notifications;
|
|
|
|
private AuthorizationServiceInterface&MockObject $authorization;
|
|
|
|
private MockObject&SessionManagerInterface $sessionManager;
|
|
|
|
private FlashServiceInterface&MockObject $flash;
|
|
|
|
private SiteController $controller;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->view = $this->makeTwigMock();
|
|
$this->settings = $this->createMock(SettingsServiceInterface::class);
|
|
$this->auditLogger = $this->createMock(AuditLoggerInterface::class);
|
|
$this->auditLogReader = $this->createMock(AuditLogReaderInterface::class);
|
|
$this->notifications = $this->createMock(NotificationServiceInterface::class);
|
|
$this->authorization = $this->createMock(AuthorizationServiceInterface::class);
|
|
$this->sessionManager = $this->createMock(SessionManagerInterface::class);
|
|
$this->flash = $this->createMock(FlashServiceInterface::class);
|
|
|
|
$this->authorization->method('canRole')->willReturnMap([
|
|
['admin', Permission::SETTINGS_MANAGE, true],
|
|
['admin', Permission::AUDIT_LOG_VIEW, true],
|
|
['admin', Permission::NOTIFICATIONS_SEND, true],
|
|
['admin', Permission::CONTENT_MANAGE, true],
|
|
['user', Permission::SETTINGS_MANAGE, false],
|
|
['user', Permission::AUDIT_LOG_VIEW, false],
|
|
['user', Permission::NOTIFICATIONS_SEND, false],
|
|
['user', Permission::CONTENT_MANAGE, false],
|
|
]);
|
|
$this->sessionManager->method('isAdmin')->willReturn(true);
|
|
$this->sessionManager->method('isEditor')->willReturn(false);
|
|
$this->sessionManager->method('getUserId')->willReturn(1);
|
|
$this->settings->method('getString')->willReturnMap([
|
|
['site.title', 'Netslim Blog', 'Netslim Blog'],
|
|
['site.tagline', '', 'Baseline'],
|
|
['site.meta_description', '', 'Description'],
|
|
['blog.home_intro', '', 'Accueil'],
|
|
['notifications.demo_recipient', '', 'demo@example.test'],
|
|
]);
|
|
$this->settings->method('getInt')->willReturnMap([
|
|
['blog.public_posts_per_page', 6, 6],
|
|
['blog.admin_posts_per_page', 12, 12],
|
|
]);
|
|
$this->auditLogReader->method('listRecent')->willReturn([
|
|
new AuditEntryView(1, 'settings.updated', 'settings', 'blog', 1, [], '2026-03-20T12:00:00+00:00'),
|
|
]);
|
|
$this->notifications->method('recent')->willReturn([
|
|
new NotificationDispatchView(1, 'demo@example.test', 'Sujet', '@Site/emails/demo-notification.twig', 'sent', 'site.demo', null, '2026-03-20T12:00:00+00:00', '2026-03-20T12:00:01+00:00'),
|
|
]);
|
|
|
|
$this->controller = new SiteController(
|
|
$this->view,
|
|
$this->settings,
|
|
$this->auditLogger,
|
|
$this->auditLogReader,
|
|
$this->notifications,
|
|
$this->authorization,
|
|
$this->sessionManager,
|
|
$this->flash,
|
|
);
|
|
}
|
|
|
|
public function testSettingsPageRedirectsWhenPermissionIsMissing(): void
|
|
{
|
|
$sessionManager = $this->createMock(SessionManagerInterface::class);
|
|
$sessionManager->method('isAdmin')->willReturn(false);
|
|
$sessionManager->method('isEditor')->willReturn(false);
|
|
$sessionManager->method('getUserId')->willReturn(1);
|
|
|
|
$authorization = $this->createMock(AuthorizationServiceInterface::class);
|
|
$authorization->expects($this->once())
|
|
->method('canRole')
|
|
->with('user', Permission::SETTINGS_MANAGE)
|
|
->willReturn(false);
|
|
|
|
$controller = new SiteController(
|
|
$this->view,
|
|
$this->settings,
|
|
$this->auditLogger,
|
|
$this->auditLogReader,
|
|
$this->notifications,
|
|
$authorization,
|
|
$sessionManager,
|
|
$this->flash,
|
|
);
|
|
|
|
$this->flash->expects($this->once())->method('set')->with('site_error', $this->stringContains('réglages'));
|
|
|
|
$response = $controller->settings($this->makeGet('/admin/settings'), $this->makeResponse());
|
|
|
|
$this->assertRedirectTo($response, '/admin');
|
|
}
|
|
|
|
public function testSaveSettingsPersistsValuesAndAuditsChange(): void
|
|
{
|
|
$this->settings->expects($this->exactly(7))->method('set');
|
|
$this->auditLogger->expects($this->once())->method('record')->with(
|
|
'settings.updated',
|
|
'settings',
|
|
'blog',
|
|
1,
|
|
$this->callback(fn (array $context): bool => isset($context['keys']) && count($context['keys']) === 7),
|
|
);
|
|
$this->flash->expects($this->once())->method('set')->with('site_success', $this->stringContains('réglages'));
|
|
|
|
$response = $this->controller->saveSettings($this->makePost('/admin/settings', [
|
|
'site_title' => 'Mon blog',
|
|
'site_tagline' => 'Baseline',
|
|
'site_meta_description' => 'Description',
|
|
'home_intro' => 'Accueil',
|
|
'public_posts_per_page' => '8',
|
|
'admin_posts_per_page' => '16',
|
|
'demo_recipient' => 'demo@example.test',
|
|
]), $this->makeResponse());
|
|
|
|
$this->assertRedirectTo($response, '/admin/settings');
|
|
}
|
|
|
|
public function testSendNotificationUsesNotificationServiceAndWritesAuditEntry(): void
|
|
{
|
|
$this->notifications->expects($this->once())->method('sendTemplate')->with(
|
|
'demo@example.test',
|
|
'Sujet',
|
|
'@Site/emails/demo-notification.twig',
|
|
$this->callback(static fn (mixed $context): bool => is_array($context)),
|
|
'site.demo-notification',
|
|
);
|
|
$this->auditLogger->expects($this->once())->method('record')->with(
|
|
'notification.sent',
|
|
'notification',
|
|
'demo@example.test',
|
|
1,
|
|
$this->callback(fn (array $context): bool => ($context['subject'] ?? null) === 'Sujet'),
|
|
);
|
|
|
|
$response = $this->controller->sendNotification($this->makePost('/admin/notifications/send', [
|
|
'recipient' => 'demo@example.test',
|
|
'subject' => 'Sujet',
|
|
]), $this->makeResponse());
|
|
|
|
$this->assertRedirectTo($response, '/admin/notifications');
|
|
}
|
|
}
|