add notifications logic and add support of both JWT and Sanctum
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationActiveService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationActiveServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_list_filters_by_target_group(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
[
|
||||
'id' => 1,
|
||||
'title' => 'Parent',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'scheduled_at' => now()->subHour(),
|
||||
'expires_at' => now()->addHour(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'title' => 'Teacher',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'teacher',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'scheduled_at' => now()->subHour(),
|
||||
'expires_at' => now()->addHour(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
|
||||
$service = new NotificationActiveService();
|
||||
$result = $service->list('parent');
|
||||
|
||||
$this->assertCount(1, $result['notifications']);
|
||||
$this->assertFalse($result['notifications'][0]['isExpired']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationCleanupService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationCleanupServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_cleanup_expired_soft_deletes_rows(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
[
|
||||
'id' => 1,
|
||||
'title' => 'Old',
|
||||
'message' => 'Old',
|
||||
'target_group' => 'all',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'priority' => 1,
|
||||
'status' => 'sent',
|
||||
'scheduled_at' => now()->subDays(2),
|
||||
'expires_at' => now()->subDay(),
|
||||
'school_year' => '2024-2025',
|
||||
'semester' => 'Spring',
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'title' => 'Active',
|
||||
'message' => 'Active',
|
||||
'target_group' => 'all',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'priority' => 1,
|
||||
'status' => 'sent',
|
||||
'scheduled_at' => now()->subDay(),
|
||||
'expires_at' => now()->addDay(),
|
||||
'school_year' => '2024-2025',
|
||||
'semester' => 'Spring',
|
||||
],
|
||||
]);
|
||||
|
||||
$service = new NotificationCleanupService();
|
||||
$deleted = $service->cleanupExpired();
|
||||
|
||||
$this->assertSame(1, $deleted);
|
||||
$this->assertSoftDeleted('notifications', ['id' => 1]);
|
||||
$this->assertDatabaseHas('notifications', ['id' => 2]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationDeletedService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationDeletedServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_list_returns_deleted_notifications(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
'id' => 1,
|
||||
'title' => 'Deleted',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'deleted_at' => now(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$service = new NotificationDeletedService();
|
||||
$result = $service->list();
|
||||
|
||||
$this->assertCount(1, $result['notifications']);
|
||||
$this->assertSame(1, $result['notifications'][0]['id']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationDispatchService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationDispatchServiceTest extends TestCase
|
||||
{
|
||||
public function test_dispatch_logs_email_and_sms(): void
|
||||
{
|
||||
Log::spy();
|
||||
|
||||
$service = new NotificationDispatchService();
|
||||
$service->sendEmail('parent@example.com', 'Subject', 'Message');
|
||||
$service->sendSms('5551112222', 'Message');
|
||||
|
||||
Log::shouldHaveReceived('info')->twice();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationManagementService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationManagementServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_update_modifies_notification(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
'id' => 1,
|
||||
'title' => 'Old',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$service = new NotificationManagementService();
|
||||
$result = $service->update(1, ['title' => 'New']);
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertDatabaseHas('notifications', [
|
||||
'id' => 1,
|
||||
'title' => 'New',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_update_returns_false_when_missing(): void
|
||||
{
|
||||
$service = new NotificationManagementService();
|
||||
$result = $service->update(999, ['title' => 'New']);
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
}
|
||||
|
||||
public function test_delete_and_restore_notification(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
'id' => 1,
|
||||
'title' => 'Old',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
$service = new NotificationManagementService();
|
||||
$this->assertTrue($service->delete(1));
|
||||
$this->assertSoftDeleted('notifications', ['id' => 1]);
|
||||
|
||||
$this->assertTrue($service->restore(1));
|
||||
$this->assertDatabaseHas('notifications', [
|
||||
'id' => 1,
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationReadService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationReadServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_mark_read_updates_row(): void
|
||||
{
|
||||
DB::table('user_notifications')->insert([
|
||||
'notification_id' => 1,
|
||||
'user_id' => 1,
|
||||
'is_read' => 0,
|
||||
]);
|
||||
|
||||
$service = new NotificationReadService();
|
||||
$result = $service->markRead(1, 1);
|
||||
|
||||
$this->assertTrue($result);
|
||||
$this->assertDatabaseHas('user_notifications', [
|
||||
'notification_id' => 1,
|
||||
'user_id' => 1,
|
||||
'is_read' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mark_read_returns_false_when_missing(): void
|
||||
{
|
||||
$service = new NotificationReadService();
|
||||
|
||||
$this->assertFalse($service->markRead(1, 99));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationRecipientService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationRecipientServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_recipients_by_role(): void
|
||||
{
|
||||
DB::table('roles')->insert([
|
||||
'id' => 1,
|
||||
'name' => 'parent',
|
||||
'slug' => 'parent',
|
||||
'is_active' => 1,
|
||||
]);
|
||||
|
||||
DB::table('users')->insert([
|
||||
'id' => 10,
|
||||
'school_id' => 1,
|
||||
'firstname' => 'Parent',
|
||||
'lastname' => 'User',
|
||||
'cellphone' => '5551112222',
|
||||
'email' => 'parent@example.com',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'is_verified' => 1,
|
||||
'status' => 'Active',
|
||||
'is_suspended' => 0,
|
||||
'failed_attempts' => 0,
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => 10,
|
||||
'role_id' => 1,
|
||||
]);
|
||||
|
||||
$service = new NotificationRecipientService();
|
||||
$rows = $service->getRecipients('parent');
|
||||
|
||||
$this->assertCount(1, $rows);
|
||||
$this->assertSame('parent@example.com', $rows[0]['email']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Models\Notification;
|
||||
use App\Models\UserNotification;
|
||||
use App\Services\Notifications\NotificationDispatchService;
|
||||
use App\Services\Notifications\NotificationRecipientService;
|
||||
use App\Services\Notifications\NotificationSendService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Mockery;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationSendServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_send_creates_notification_and_user_notifications(): void
|
||||
{
|
||||
$recipients = Mockery::mock(NotificationRecipientService::class);
|
||||
$recipients->shouldReceive('getRecipients')
|
||||
->with('parent')
|
||||
->andReturn([
|
||||
['id' => 10, 'email' => 'parent1@example.com', 'phone' => '5551112222'],
|
||||
['id' => 11, 'email' => 'parent2@example.com', 'phone' => null],
|
||||
]);
|
||||
|
||||
$dispatcher = Mockery::mock(NotificationDispatchService::class);
|
||||
$dispatcher->shouldReceive('sendEmail')->once();
|
||||
$dispatcher->shouldReceive('sendSms')->once();
|
||||
|
||||
$service = new NotificationSendService($recipients, $dispatcher);
|
||||
|
||||
$result = $service->send([
|
||||
'title' => 'Announcement',
|
||||
'message' => 'Hello parents',
|
||||
'target_group' => 'parent',
|
||||
'channels' => ['in_app', 'email', 'sms'],
|
||||
], 99);
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertSame(2, $result['recipient_count']);
|
||||
$this->assertDatabaseHas('notifications', [
|
||||
'title' => 'Announcement',
|
||||
'target_group' => 'parent',
|
||||
]);
|
||||
$this->assertSame(1, Notification::query()->count());
|
||||
$this->assertSame(2, UserNotification::query()->count());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationShowService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationShowServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_for_user_returns_notification(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
'id' => 1,
|
||||
'title' => 'Hello',
|
||||
'message' => 'Message',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'scheduled_at' => now()->subHour(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
DB::table('user_notifications')->insert([
|
||||
'notification_id' => 1,
|
||||
'user_id' => 1,
|
||||
'is_read' => 0,
|
||||
]);
|
||||
|
||||
$service = new NotificationShowService();
|
||||
$row = $service->getForUser(1, 1);
|
||||
|
||||
$this->assertNotNull($row);
|
||||
$this->assertSame(1, $row['notification_id']);
|
||||
}
|
||||
|
||||
public function test_get_for_user_returns_null_when_missing(): void
|
||||
{
|
||||
$service = new NotificationShowService();
|
||||
$row = $service->getForUser(1, 99);
|
||||
|
||||
$this->assertNull($row);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationTriggerService;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationTriggerServiceTest extends TestCase
|
||||
{
|
||||
public function test_trigger_dispatches_event(): void
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
NotificationTriggerService::trigger('customNotification', ['foo' => 'bar']);
|
||||
|
||||
Event::assertDispatched('customNotification');
|
||||
}
|
||||
|
||||
public function test_to_user_dispatches_event(): void
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
NotificationTriggerService::toUser(5, 'Hello', 'Message');
|
||||
|
||||
Event::assertDispatched('customNotification');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\NotificationUserListService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NotificationUserListServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_list_filters_by_read_status(): void
|
||||
{
|
||||
DB::table('notifications')->insert([
|
||||
[
|
||||
'id' => 1,
|
||||
'title' => 'Unread',
|
||||
'message' => 'Message 1',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'scheduled_at' => now()->subHour(),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'title' => 'Read',
|
||||
'message' => 'Message 2',
|
||||
'target_group' => 'parent',
|
||||
'delivery_channels' => json_encode(['in_app']),
|
||||
'scheduled_at' => now()->subHours(2),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
|
||||
DB::table('user_notifications')->insert([
|
||||
[
|
||||
'notification_id' => 1,
|
||||
'user_id' => 1,
|
||||
'is_read' => 0,
|
||||
],
|
||||
[
|
||||
'notification_id' => 2,
|
||||
'user_id' => 1,
|
||||
'is_read' => 1,
|
||||
],
|
||||
]);
|
||||
|
||||
$service = new NotificationUserListService();
|
||||
$result = $service->listForUser(1, [
|
||||
'read' => true,
|
||||
'per_page' => 10,
|
||||
]);
|
||||
|
||||
$this->assertSame(1, $result['pagination']['total']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Services\Notifications;
|
||||
|
||||
use App\Services\Notifications\UserNotificationDispatchService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserNotificationDispatchServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_notify_user_creates_notification(): void
|
||||
{
|
||||
DB::table('users')->insert([
|
||||
'id' => 1,
|
||||
'school_id' => 1,
|
||||
'firstname' => 'Parent',
|
||||
'lastname' => 'User',
|
||||
'cellphone' => '5551112222',
|
||||
'email' => 'parent@example.com',
|
||||
'address_street' => '123 Main',
|
||||
'city' => 'City',
|
||||
'state' => 'ST',
|
||||
'zip' => '12345',
|
||||
'accept_school_policy' => 1,
|
||||
'is_verified' => 1,
|
||||
'status' => 'Active',
|
||||
'is_suspended' => 0,
|
||||
'failed_attempts' => 0,
|
||||
'password' => bcrypt('secret'),
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2025-2026',
|
||||
]);
|
||||
|
||||
$service = new UserNotificationDispatchService();
|
||||
$result = $service->notifyUser(1, 'Title', 'Message', ['in_app'], 'registration', 'parent');
|
||||
|
||||
$this->assertTrue($result['ok']);
|
||||
$this->assertDatabaseHas('notifications', [
|
||||
'title' => 'Title',
|
||||
'target_group' => 'parent',
|
||||
]);
|
||||
$this->assertDatabaseHas('user_notifications', [
|
||||
'user_id' => 1,
|
||||
'is_read' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_notify_user_rejects_invalid_user(): void
|
||||
{
|
||||
$service = new UserNotificationDispatchService();
|
||||
$result = $service->notifyUser(0, 'Title', 'Message');
|
||||
|
||||
$this->assertFalse($result['ok']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user