diff --git a/app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php b/app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php new file mode 100644 index 00000000..6582e41f --- /dev/null +++ b/app/Exceptions/Api/CanNotRemoveOwnerFromOrganization.php @@ -0,0 +1,10 @@ +whereBelongsToOrganization($organization)->where('user_id', $member->user_id)->exists()) { throw new EntityStillInUseApiException('member', 'project_member'); } + if ($member->role === Role::Owner->value) { + throw new CanNotRemoveOwnerFromOrganization(); + } $member->delete(); diff --git a/lang/en/exceptions.php b/lang/en/exceptions.php index 8a819eae..fa2bf17b 100644 --- a/lang/en/exceptions.php +++ b/lang/en/exceptions.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use App\Exceptions\Api\CanNotRemoveOwnerFromOrganization; use App\Exceptions\Api\EntityStillInUseApiException; use App\Exceptions\Api\InactiveUserCanNotBeUsedApiException; use App\Exceptions\Api\TimeEntryCanNotBeRestartedApiException; @@ -17,5 +18,6 @@ return [ InactiveUserCanNotBeUsedApiException::KEY => 'Inactive user can not be used', UserIsAlreadyMemberOfProjectApiException::KEY => 'User is already a member of the project', EntityStillInUseApiException::KEY => 'The :modelToDelete is still used by a :modelInUse and can not be deleted.', + CanNotRemoveOwnerFromOrganization::KEY => 'Can not remove owner from organization', ], ]; diff --git a/tests/Unit/Endpoint/Api/V1/MemberEndpointTest.php b/tests/Unit/Endpoint/Api/V1/MemberEndpointTest.php index 2534f6dc..afd955c9 100644 --- a/tests/Unit/Endpoint/Api/V1/MemberEndpointTest.php +++ b/tests/Unit/Endpoint/Api/V1/MemberEndpointTest.php @@ -141,6 +141,23 @@ class MemberEndpointTest extends ApiEndpointTestAbstract $response->assertStatus(403); } + public function test_destroy_member_fails_if_member_is_owner(): void + { + // Arrange + $data = $this->createUserWithPermission([ + 'members:delete', + ]); + $memberToDelete = Member::factory()->forOrganization($data->organization)->role(Role::Owner)->create(); + Passport::actingAs($data->user); + + // Act + $response = $this->deleteJson(route('api.v1.members.destroy', [$data->organization->getKey(), $memberToDelete->getKey()])); + + // Assert + $response->assertStatus(400); + $response->assertJsonPath('message', 'Can not remove owner from organization'); + } + public function test_destroy_member_fails_if_member_is_not_part_of_org(): void { // Arrange diff --git a/tests/Unit/Service/Import/ImportServiceTest.php b/tests/Unit/Service/Import/ImportServiceTest.php index 27bfc5c4..0e34ba23 100644 --- a/tests/Unit/Service/Import/ImportServiceTest.php +++ b/tests/Unit/Service/Import/ImportServiceTest.php @@ -7,6 +7,7 @@ namespace Tests\Unit\Service\Import; use App\Models\Organization; use App\Service\Import\ImportService; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Storage; use Tests\TestCase; class ImportServiceTest extends TestCase @@ -16,6 +17,7 @@ class ImportServiceTest extends TestCase public function test_import_gets_importer_from_provider_runs_importer_and_returns_report(): void { // Arrange + Storage::fake('s3'); $organization = Organization::factory()->create(); $data = file_get_contents(storage_path('tests/toggl_time_entries_import_test_1.csv'));