CRM/backend/tests/Feature/SecurityAuthorizationTest.php

237 خطوط
8.0 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Call;
use App\Models\FollowUp;
use App\Models\Lead;
use App\Models\Setting;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Tests\TestCase;
class SecurityAuthorizationTest extends TestCase
{
use RefreshDatabase;
public function test_guest_cannot_access_authenticated_api_routes(): void
{
$this->getJson('/api/leads')->assertUnauthorized();
$this->postJson('/api/auth/logout')->assertUnauthorized();
}
public function test_agent_cannot_modify_another_agents_lead(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$this->actingAs($agent)
->putJson("/api/leads/{$lead->id}", ['company' => 'Tampered Co'])
->assertForbidden();
$this->assertDatabaseMissing('leads', [
'id' => $lead->id,
'company' => 'Tampered Co',
]);
}
public function test_agent_cannot_delete_another_agents_lead(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$this->actingAs($agent)
->deleteJson("/api/leads/{$lead->id}")
->assertForbidden();
$this->assertDatabaseHas('leads', ['id' => $lead->id, 'deleted_at' => null]);
}
public function test_agent_cannot_bulk_delete_another_agents_leads(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$this->actingAs($agent)
->deleteJson('/api/leads/bulk-delete', ['ids' => [$lead->id]])
->assertForbidden();
$this->assertDatabaseHas('leads', ['id' => $lead->id, 'deleted_at' => null]);
}
public function test_agent_cannot_reassign_leads(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$this->actingAs($agent)
->postJson('/api/assignments/reassign', [
'lead_id' => $lead->id,
'agent_id' => $agent->id,
])
->assertForbidden();
$this->assertDatabaseHas('leads', [
'id' => $lead->id,
'assigned_to' => $otherAgent->id,
]);
}
public function test_agent_cannot_modify_another_users_follow_up(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$followUp = FollowUp::create([
'lead_id' => $lead->id,
'user_id' => $otherAgent->id,
'scheduled_at' => now()->addDay(),
'status' => 'pending',
]);
$this->actingAs($agent)
->patchJson("/api/follow-ups/{$followUp->id}/mark-done")
->assertForbidden();
$this->assertDatabaseHas('follow_ups', [
'id' => $followUp->id,
'status' => 'pending',
]);
}
public function test_agent_cannot_view_or_register_result_for_another_agents_call(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$call = Call::create([
'lead_id' => $lead->id,
'user_id' => $otherAgent->id,
'direction' => 'outbound',
'phone' => '09129998877',
]);
$this->actingAs($agent)
->getJson("/api/calls/{$call->id}")
->assertForbidden();
$this->actingAs($agent)
->postJson('/api/calls/register-result', [
'call_id' => $call->id,
'result' => 'پاسخ داد',
])
->assertForbidden();
$this->assertDatabaseHas('calls', [
'id' => $call->id,
'result' => null,
]);
}
public function test_agent_cannot_create_follow_up_for_unauthorized_lead(): void
{
[$agent, $otherAgent] = $this->makeAgents();
$lead = $this->makeLead(['assigned_to' => $otherAgent->id, 'is_unassigned' => false]);
$this->actingAs($agent)
->postJson('/api/follow-ups', [
'lead_id' => $lead->id,
'scheduled_at' => now()->addDay()->toISOString(),
'notes' => 'Unauthorized follow-up',
])
->assertForbidden();
$this->assertDatabaseMissing('follow_ups', [
'lead_id' => $lead->id,
'user_id' => $agent->id,
]);
}
public function test_phone_numbers_and_recordings_are_masked_without_permissions(): void
{
[$agent] = $this->makeAgents();
Setting::create(['key' => 'phone_mask_enabled', 'value' => 'true', 'group' => 'security', 'type' => 'boolean']);
$lead = $this->makeLead([
'assigned_to' => $agent->id,
'is_unassigned' => false,
'phone' => '09121234567',
'phone_secondary' => '02199887766',
]);
$call = Call::create([
'lead_id' => $lead->id,
'user_id' => $agent->id,
'direction' => 'outbound',
'phone' => '09121234567',
'recording_url' => 'https://recordings.example.test/call.mp3',
]);
$response = $this->actingAs($agent)
->getJson("/api/calls/{$call->id}")
->assertOk();
$this->assertStringNotContainsString('09121234567', $response->getContent());
$response->assertJsonPath('data.recording_url', null);
}
public function test_supervisor_cannot_access_other_team_lead_or_report(): void
{
$supervisorRole = Role::create(['name' => 'supervisor', 'guard_name' => 'web']);
$agentRole = Role::create(['name' => 'agent', 'guard_name' => 'web']);
$supervisor = User::factory()->create(['is_active' => true]);
$ownAgent = User::factory()->create(['is_active' => true]);
$otherAgent = User::factory()->create(['is_active' => true]);
$supervisor->assignRole($supervisorRole);
Permission::create(['name' => 'view_reports', 'guard_name' => 'web']);
$supervisor->givePermissionTo('view_reports');
$ownAgent->assignRole($agentRole);
$otherAgent->assignRole($agentRole);
$ownTeam = Team::create(['name' => 'Own Team', 'supervisor_id' => $supervisor->id, 'is_active' => true]);
$otherTeam = Team::create(['name' => 'Other Team', 'is_active' => true]);
$supervisor->teams()->attach($ownTeam->id);
$ownAgent->teams()->attach($ownTeam->id);
$otherAgent->teams()->attach($otherTeam->id);
$otherLead = $this->makeLead([
'assigned_to' => $otherAgent->id,
'team_id' => $otherTeam->id,
'is_unassigned' => false,
]);
$this->actingAs($supervisor)
->getJson("/api/leads/{$otherLead->id}")
->assertForbidden();
$this->actingAs($supervisor)
->getJson("/api/reports/agent-performance?agent_id={$otherAgent->id}")
->assertForbidden();
}
/**
* @return array{0: User, 1: User}
*/
private function makeAgents(): array
{
$agentRole = Role::create(['name' => 'agent', 'guard_name' => 'web']);
$agent = User::factory()->create(['is_active' => true]);
$otherAgent = User::factory()->create(['is_active' => true]);
$agent->assignRole($agentRole);
$otherAgent->assignRole($agentRole);
return [$agent, $otherAgent];
}
private function makeLead(array $attributes = []): Lead
{
return Lead::create(array_merge([
'company' => 'Acme',
'first_name' => 'Ali',
'last_name' => 'Karimi',
'phone' => fake()->unique()->numerify('021########'),
], $attributes));
}
}