Implement tenant announcements and audit log fixes
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-02 14:19:46 +01:00
parent 412ecbe691
commit 8f13465415
33 changed files with 1400 additions and 117 deletions

View File

@@ -0,0 +1,68 @@
<?php
namespace Tests\Feature\Api\Tenant;
use App\Enums\TenantAnnouncementAudience;
use App\Enums\TenantAnnouncementSegment;
use App\Enums\TenantAnnouncementStatus;
use App\Models\Tenant;
use App\Models\TenantAnnouncement;
use App\Models\TenantPackage;
use Tests\Feature\Tenant\TenantTestCase;
class TenantAnnouncementsTest extends TenantTestCase
{
public function test_announcements_endpoint_returns_targeted_active_announcements(): void
{
$otherTenant = Tenant::factory()->create();
$activeAll = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::ALL,
]);
$targeted = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::TENANTS,
]);
$targeted->tenants()->attach($this->tenant->id);
$segmentActive = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::SEGMENTS,
'segments' => [TenantAnnouncementSegment::ACTIVE_STATUS->value],
]);
$segmentPackage = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::SEGMENTS,
'segments' => [TenantAnnouncementSegment::ACTIVE_PACKAGE->value],
]);
TenantPackage::factory()->for($this->tenant)->create(['active' => true]);
$otherTargeted = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::TENANTS,
]);
$otherTargeted->tenants()->attach($otherTenant->id);
$draft = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::DRAFT,
'audience' => TenantAnnouncementAudience::ALL,
]);
$response = $this->authenticatedRequest('GET', '/api/v1/tenant/announcements');
$response->assertOk();
$ids = collect($response->json('data'))->pluck('id');
$this->assertTrue($ids->contains($activeAll->id));
$this->assertTrue($ids->contains($targeted->id));
$this->assertTrue($ids->contains($segmentActive->id));
$this->assertTrue($ids->contains($segmentPackage->id));
$this->assertFalse($ids->contains($otherTargeted->id));
$this->assertFalse($ids->contains($draft->id));
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Tests\Feature\Console;
use App\Enums\TenantAnnouncementAudience;
use App\Enums\TenantAnnouncementDeliveryStatus;
use App\Enums\TenantAnnouncementStatus;
use App\Models\Tenant;
use App\Models\TenantAnnouncement;
use App\Models\TenantAnnouncementDelivery;
use App\Models\User;
use App\Notifications\TenantAnnouncementNotification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;
class DispatchTenantAnnouncementsCommandTest extends TestCase
{
use RefreshDatabase;
public function test_dispatches_email_notifications_for_active_announcements(): void
{
Notification::fake();
$tenant = Tenant::factory()->create(['contact_email' => 'owner@example.com']);
$user = User::factory()->create(['tenant_id' => $tenant->id]);
$tenant->user()->associate($user)->save();
$announcement = TenantAnnouncement::factory()->create([
'status' => TenantAnnouncementStatus::ACTIVE,
'audience' => TenantAnnouncementAudience::ALL,
'email_enabled' => true,
]);
$this->artisan('tenant-announcements:dispatch')->assertExitCode(0);
Notification::assertSentOnDemand(
TenantAnnouncementNotification::class,
function (TenantAnnouncementNotification $notification, array $channels, $notifiable) use ($announcement, $tenant): bool {
$payload = $notification->toArray($notifiable);
return in_array('mail', $channels, true)
&& $payload['announcement_id'] === $announcement->id
&& $payload['tenant_id'] === $tenant->id;
}
);
$this->assertTrue(TenantAnnouncementDelivery::query()
->where('tenant_announcement_id', $announcement->id)
->where('tenant_id', $tenant->id)
->where('channel', 'mail')
->where('status', TenantAnnouncementDeliveryStatus::QUEUED)
->exists());
}
}

View File

@@ -2,7 +2,9 @@
namespace Tests\Feature;
use App\Filament\Resources\EventResource\Pages\ManageWatermark;
use App\Filament\SuperAdmin\Pages\GuestPolicySettingsPage;
use App\Models\Event;
use App\Models\SuperAdminActionLog;
use App\Models\User;
use Filament\Facades\Filament;
@@ -29,6 +31,24 @@ class SuperAdminAuditLogSettingsTest extends TestCase
->exists());
}
public function test_event_watermark_save_creates_audit_log(): void
{
$user = User::factory()->create(['role' => 'super_admin']);
$event = Event::factory()->create();
$this->bootSuperAdminPanel($user);
Livewire::test(ManageWatermark::class, ['record' => $event->getKey()])
->set('watermark_mode', 'base')
->set('watermark_position', 'top-left')
->call('save');
$this->assertTrue(SuperAdminActionLog::query()
->where('action', 'event.watermark_updated')
->where('subject_id', $event->id)
->exists());
}
private function bootSuperAdminPanel(User $user): void
{
$panel = Filament::getPanel('superadmin');