441 lines
14 KiB
PHP
441 lines
14 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Contact;
|
|
use App\Models\ContactGroup;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class ContactManagementTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_authenticated_user_can_create_group_and_local_contact(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post('/contact-groups', [
|
|
'name' => 'Benevoles',
|
|
'description' => 'Equipe locale',
|
|
'is_favorite' => '1',
|
|
])
|
|
->assertRedirect('/contacts');
|
|
|
|
$group = ContactGroup::query()->where('name', 'Benevoles')->firstOrFail();
|
|
|
|
$response = $this->actingAs($user)
|
|
->post('/contacts', [
|
|
'first_name' => 'Marie',
|
|
'last_name' => 'Durand',
|
|
'organization' => 'AFPMA',
|
|
'email' => 'marie@example.test',
|
|
'raw_phone_number' => '06 11 11 00 03',
|
|
'phone_label' => 'Mobile',
|
|
'group_ids' => [$group->id],
|
|
'sms_opt_out' => '1',
|
|
'is_favorite' => '1',
|
|
]);
|
|
|
|
$contact = Contact::query()->where('email', 'marie@example.test')->firstOrFail();
|
|
|
|
$response->assertRedirect(route('contacts.show', $contact));
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'source' => 'local',
|
|
'sms_opt_out' => true,
|
|
'is_favorite' => true,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('contact_contact_group', [
|
|
'contact_id' => $contact->id,
|
|
'contact_group_id' => $group->id,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('contact_phone_numbers', [
|
|
'contact_id' => $contact->id,
|
|
'raw_number' => '06 11 11 00 03',
|
|
'normalized_number' => '+33611110003',
|
|
'country' => 'FR',
|
|
'is_valid' => true,
|
|
'is_mobile' => true,
|
|
]);
|
|
}
|
|
|
|
public function test_contacts_can_be_searched_by_name_and_phone_number(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Jean',
|
|
'last_name' => 'Martin',
|
|
'email' => 'jean@example.test',
|
|
]);
|
|
|
|
$contact->phoneNumbers()->create([
|
|
'raw_number' => '06 11 11 00 01',
|
|
'normalized_number' => '+33611110001',
|
|
'country' => 'FR',
|
|
'is_valid' => true,
|
|
'is_mobile' => true,
|
|
'is_primary' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get('/contacts?q=Martin')
|
|
->assertOk()
|
|
->assertSee('Jean Martin')
|
|
->assertSee('+33611110001');
|
|
|
|
$this->actingAs($user)
|
|
->get('/contacts?q=11110001')
|
|
->assertOk()
|
|
->assertSee('Jean Martin');
|
|
}
|
|
|
|
public function test_contacts_default_mobile_filter_includes_stale_normalized_mobile_numbers(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'carddav',
|
|
'external_id' => 'uid-yveline',
|
|
'first_name' => 'Yveline',
|
|
'last_name' => 'Mobile',
|
|
]);
|
|
$contact->phoneNumbers()->create([
|
|
'raw_number' => '064-201-4207',
|
|
'normalized_number' => '+33642014207',
|
|
'country' => 'FR',
|
|
'is_valid' => true,
|
|
'is_mobile' => false,
|
|
'is_primary' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get('/contacts')
|
|
->assertOk()
|
|
->assertSee('Yveline Mobile')
|
|
->assertSee('Mobile detecte');
|
|
}
|
|
|
|
public function test_authenticated_user_can_update_contact(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$oldGroup = ContactGroup::query()->create([
|
|
'source' => 'local',
|
|
'name' => 'Anciens',
|
|
'slug' => 'anciens',
|
|
]);
|
|
$newGroup = ContactGroup::query()->create([
|
|
'source' => 'local',
|
|
'name' => 'Membres',
|
|
'slug' => 'membres',
|
|
]);
|
|
$contact = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Jean',
|
|
'last_name' => 'Martin',
|
|
'email' => 'jean@example.test',
|
|
]);
|
|
$contact->groups()->attach($oldGroup);
|
|
$contact->phoneNumbers()->create([
|
|
'label' => 'Mobile',
|
|
'raw_number' => '06 11 11 00 01',
|
|
'normalized_number' => '+33611110001',
|
|
'country' => 'FR',
|
|
'is_valid' => true,
|
|
'is_mobile' => true,
|
|
'is_primary' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->put(route('contacts.update', $contact), [
|
|
'first_name' => 'Jeanne',
|
|
'last_name' => 'Martin',
|
|
'email' => 'jeanne@example.test',
|
|
'raw_phone_number' => '07 55 55 00 04',
|
|
'phone_label' => 'Portable',
|
|
'group_ids' => [$newGroup->id],
|
|
'is_favorite' => '1',
|
|
])
|
|
->assertRedirect(route('contacts.show', $contact));
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'first_name' => 'Jeanne',
|
|
'email' => 'jeanne@example.test',
|
|
'sms_opt_out' => false,
|
|
'is_favorite' => true,
|
|
]);
|
|
|
|
$this->assertDatabaseMissing('contact_contact_group', [
|
|
'contact_id' => $contact->id,
|
|
'contact_group_id' => $oldGroup->id,
|
|
]);
|
|
$this->assertDatabaseHas('contact_contact_group', [
|
|
'contact_id' => $contact->id,
|
|
'contact_group_id' => $newGroup->id,
|
|
]);
|
|
$this->assertDatabaseHas('contact_phone_numbers', [
|
|
'contact_id' => $contact->id,
|
|
'label' => 'Portable',
|
|
'raw_number' => '07 55 55 00 04',
|
|
'normalized_number' => '+33755550004',
|
|
'is_mobile' => true,
|
|
]);
|
|
}
|
|
|
|
public function test_imported_contacts_cannot_be_edited_or_deleted(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'carddav',
|
|
'external_id' => 'remote-1',
|
|
'first_name' => 'Jean',
|
|
'last_name' => 'Importe',
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('contacts.edit', $contact))
|
|
->assertForbidden();
|
|
|
|
$this->actingAs($user)
|
|
->put(route('contacts.update', $contact), [
|
|
'last_name' => 'Modifie',
|
|
])
|
|
->assertForbidden();
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('contacts.destroy', $contact))
|
|
->assertForbidden();
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'last_name' => 'Importe',
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
public function test_authenticated_user_can_toggle_favorite_on_imported_contact(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'carddav',
|
|
'external_id' => 'remote-favorite',
|
|
'first_name' => 'Yveline',
|
|
'last_name' => 'Importee',
|
|
'is_favorite' => false,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('contacts.favorite', $contact), [
|
|
'is_favorite' => '1',
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'source' => 'carddav',
|
|
'is_favorite' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('contacts.favorite', $contact), [
|
|
'is_favorite' => '0',
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'source' => 'carddav',
|
|
'is_favorite' => false,
|
|
]);
|
|
}
|
|
|
|
public function test_authenticated_user_can_toggle_sms_opt_out_on_imported_contact(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'galette',
|
|
'external_id' => 'remote-opt-out',
|
|
'first_name' => 'Claire',
|
|
'last_name' => 'Importee',
|
|
'sms_opt_out' => false,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('contacts.opt-out', $contact), [
|
|
'sms_opt_out' => '1',
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'source' => 'galette',
|
|
'sms_opt_out' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('contacts.opt-out', $contact), [
|
|
'sms_opt_out' => '0',
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('contacts', [
|
|
'id' => $contact->id,
|
|
'source' => 'galette',
|
|
'sms_opt_out' => false,
|
|
]);
|
|
}
|
|
|
|
public function test_authenticated_user_can_delete_contact(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$contact = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Jean',
|
|
'last_name' => 'Martin',
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('contacts.destroy', $contact))
|
|
->assertRedirect(route('contacts.index'));
|
|
|
|
$this->assertSoftDeleted('contacts', [
|
|
'id' => $contact->id,
|
|
]);
|
|
}
|
|
|
|
public function test_authenticated_user_can_update_and_delete_group(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$group = ContactGroup::query()->create([
|
|
'source' => 'local',
|
|
'name' => 'Benevoles',
|
|
'slug' => 'benevoles',
|
|
]);
|
|
$contact = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Marie',
|
|
'last_name' => 'Durand',
|
|
]);
|
|
$contact->groups()->attach($group);
|
|
|
|
$this->actingAs($user)
|
|
->put(route('contact-groups.update', $group), [
|
|
'name' => 'Equipe accueil',
|
|
'description' => 'Permanences',
|
|
'is_favorite' => '1',
|
|
])
|
|
->assertRedirect(route('contacts.index', ['group' => $group->id]));
|
|
|
|
$this->assertDatabaseHas('contact_groups', [
|
|
'id' => $group->id,
|
|
'name' => 'Equipe accueil',
|
|
'slug' => 'equipe-accueil',
|
|
'description' => 'Permanences',
|
|
'is_favorite' => true,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('contact-groups.destroy', $group))
|
|
->assertRedirect(route('contacts.index'));
|
|
|
|
$this->assertSoftDeleted('contact_groups', [
|
|
'id' => $group->id,
|
|
]);
|
|
$this->assertDatabaseMissing('contact_contact_group', [
|
|
'contact_id' => $contact->id,
|
|
'contact_group_id' => $group->id,
|
|
]);
|
|
}
|
|
|
|
public function test_authenticated_user_can_update_local_group_members(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$group = ContactGroup::query()->create([
|
|
'source' => 'local',
|
|
'name' => 'Benevoles',
|
|
'slug' => 'benevoles',
|
|
]);
|
|
$kept = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Marie',
|
|
'last_name' => 'Durand',
|
|
]);
|
|
$removed = Contact::query()->create([
|
|
'source' => 'local',
|
|
'first_name' => 'Paul',
|
|
'last_name' => 'Ancien',
|
|
]);
|
|
$addedImported = Contact::query()->create([
|
|
'source' => 'carddav',
|
|
'external_id' => 'remote-added',
|
|
'first_name' => 'Claire',
|
|
'last_name' => 'Importee',
|
|
]);
|
|
$group->contacts()->attach([$kept->id, $removed->id]);
|
|
|
|
$this->actingAs($user)
|
|
->put(route('contact-groups.update', $group), [
|
|
'name' => 'Benevoles',
|
|
'members_submitted' => '1',
|
|
'contact_ids' => [$kept->id, $addedImported->id],
|
|
])
|
|
->assertRedirect(route('contacts.index', ['group' => $group->id]));
|
|
|
|
$this->assertDatabaseHas('contact_contact_group', [
|
|
'contact_id' => $kept->id,
|
|
'contact_group_id' => $group->id,
|
|
]);
|
|
$this->assertDatabaseHas('contact_contact_group', [
|
|
'contact_id' => $addedImported->id,
|
|
'contact_group_id' => $group->id,
|
|
]);
|
|
$this->assertDatabaseMissing('contact_contact_group', [
|
|
'contact_id' => $removed->id,
|
|
'contact_group_id' => $group->id,
|
|
]);
|
|
}
|
|
|
|
public function test_imported_groups_cannot_be_edited_or_deleted(): void
|
|
{
|
|
$user = User::factory()->create();
|
|
$group = ContactGroup::query()->create([
|
|
'source' => 'galette',
|
|
'external_id' => 'remote-group',
|
|
'name' => 'Groupe importe',
|
|
'slug' => 'galette-groupe-importe',
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('contact-groups.edit', $group))
|
|
->assertForbidden();
|
|
|
|
$this->actingAs($user)
|
|
->put(route('contact-groups.update', $group), [
|
|
'name' => 'Modifie',
|
|
])
|
|
->assertForbidden();
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('contact-groups.destroy', $group))
|
|
->assertForbidden();
|
|
|
|
$this->assertDatabaseHas('contact_groups', [
|
|
'id' => $group->id,
|
|
'name' => 'Groupe importe',
|
|
'deleted_at' => null,
|
|
]);
|
|
}
|
|
|
|
public function test_guest_cannot_access_contacts(): void
|
|
{
|
|
$this->get('/contacts')
|
|
->assertRedirect('/login');
|
|
}
|
|
}
|