diff --git a/app/Actions/User/DeleteUserResources.php b/app/Actions/User/DeleteUserResources.php index 3c539d7c5..b6ed5f9ab 100644 --- a/app/Actions/User/DeleteUserResources.php +++ b/app/Actions/User/DeleteUserResources.php @@ -70,7 +70,7 @@ class DeleteUserResources return [ 'applications' => $applications->unique('id'), - 'databases' => $databases->unique('id'), + 'databases' => $databases->unique(fn ($database) => $database::class.':'.$database->id), 'services' => $services->unique('id'), ]; } diff --git a/app/Models/Project.php b/app/Models/Project.php index ba560a840..ab088af3d 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -166,13 +166,13 @@ class Project extends BaseModel public function databases(array $with = []): Collection { return $this->postgresqls()->with($with)->get() - ->merge($this->redis()->with($with)->get()) - ->merge($this->mongodbs()->with($with)->get()) - ->merge($this->mysqls()->with($with)->get()) - ->merge($this->mariadbs()->with($with)->get()) - ->merge($this->keydbs()->with($with)->get()) - ->merge($this->dragonflies()->with($with)->get()) - ->merge($this->clickhouses()->with($with)->get()); + ->concat($this->redis()->with($with)->get()) + ->concat($this->mongodbs()->with($with)->get()) + ->concat($this->mysqls()->with($with)->get()) + ->concat($this->mariadbs()->with($with)->get()) + ->concat($this->keydbs()->with($with)->get()) + ->concat($this->dragonflies()->with($with)->get()) + ->concat($this->clickhouses()->with($with)->get()); } public function navigateTo() diff --git a/app/Models/Team.php b/app/Models/Team.php index e1593652a..4ef20729d 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -107,7 +107,7 @@ class Team extends Model implements SendsDiscord, SendsEmail, SendsPushover, Sen // Delete non-instance-wide sources owned by this team $teamSources = GithubApp::where('team_id', $team->id)->get() - ->merge(GitlabApp::where('team_id', $team->id)->get()); + ->concat(GitlabApp::where('team_id', $team->id)->get()); foreach ($teamSources as $source) { $source->delete(); } diff --git a/tests/Feature/ProjectDatabasesTest.php b/tests/Feature/ProjectDatabasesTest.php new file mode 100644 index 000000000..592e14d5c --- /dev/null +++ b/tests/Feature/ProjectDatabasesTest.php @@ -0,0 +1,40 @@ +create(); + $server = Server::factory()->create(['team_id' => $team->id]); + $destination = StandaloneDocker::where('server_id', $server->id)->firstOrFail(); + $project = Project::factory()->create(['team_id' => $team->id]); + $environment = $project->environments()->firstOrFail(); + + StandaloneRedis::forceCreate([ + 'id' => 42, + 'name' => 'redis', + 'environment_id' => $environment->id, + 'destination_id' => $destination->id, + 'destination_type' => $destination->getMorphClass(), + ]); + StandaloneMariadb::forceCreate([ + 'id' => 42, + 'name' => 'mariadb', + 'mariadb_root_password' => 'password', + 'mariadb_password' => 'password', + 'environment_id' => $environment->id, + 'destination_id' => $destination->id, + 'destination_type' => $destination->getMorphClass(), + ]); + + expect($project->redis()->count())->toBe(1) + ->and($project->mariadbs()->count())->toBe(1) + ->and($project->databases())->toHaveCount(2); +}); diff --git a/tests/Feature/Team/TeamDeletionTest.php b/tests/Feature/Team/TeamDeletionTest.php index ed6ee8a4f..6bdcaf4e8 100644 --- a/tests/Feature/Team/TeamDeletionTest.php +++ b/tests/Feature/Team/TeamDeletionTest.php @@ -1,6 +1,8 @@ toBeNull(); }); + +test('deleting a team deletes github and gitlab sources with the same primary key', function () { + $githubApp = GithubApp::forceCreate([ + 'id' => 42, + 'name' => 'GitHub source', + 'team_id' => $this->teamToDelete->id, + 'api_url' => 'https://api.github.com', + 'html_url' => 'https://github.com', + 'is_public' => false, + ]); + $gitlabApp = GitlabApp::forceCreate([ + 'id' => 42, + 'name' => 'GitLab source', + 'team_id' => $this->teamToDelete->id, + 'api_url' => 'https://gitlab.com/api/v4', + 'html_url' => 'https://gitlab.com', + 'is_public' => false, + ]); + + $this->teamToDelete->delete(); + + expect(GithubApp::find($githubApp->id))->toBeNull() + ->and(GitlabApp::find($gitlabApp->id))->toBeNull(); +}); diff --git a/tests/Unit/Actions/User/DeleteUserResourcesTest.php b/tests/Unit/Actions/User/DeleteUserResourcesTest.php index 3a623fee6..940d56565 100644 --- a/tests/Unit/Actions/User/DeleteUserResourcesTest.php +++ b/tests/Unit/Actions/User/DeleteUserResourcesTest.php @@ -2,6 +2,8 @@ use App\Actions\User\DeleteUserResources; use App\Models\Server; +use App\Models\StandaloneMariadb; +use App\Models\StandaloneRedis; use App\Models\Team; use App\Models\User; @@ -16,6 +18,38 @@ afterEach(function () { Mockery::close(); }); +it('keeps different database types with the same primary key in the preview', function () { + $teamPivot = (object) ['role' => 'owner']; + $team = Mockery::mock(Team::class); + $team->shouldReceive('getAttribute')->with('pivot')->andReturn($teamPivot); + $team->shouldReceive('getAttribute')->with('members')->andReturn(collect([$this->user])); + $team->shouldReceive('setAttribute')->andReturnSelf(); + $team->pivot = $teamPivot; + $team->members = collect([$this->user]); + + $redis = new StandaloneRedis; + $redis->id = 42; + $mariadb = new StandaloneMariadb; + $mariadb->id = 42; + + $server = Mockery::mock(Server::class); + $server->shouldReceive('applications')->andReturn(collect()); + $server->shouldReceive('databases')->andReturn(collect([$redis, $mariadb])); + $server->shouldReceive('services->get')->andReturn(collect()); + + $teamsRelation = Mockery::mock(); + $teamsRelation->shouldReceive('get')->andReturn(collect([$team])); + $this->user->shouldReceive('teams')->andReturn($teamsRelation); + + $serversRelation = Mockery::mock(); + $serversRelation->shouldReceive('get')->andReturn(collect([$server])); + $team->shouldReceive('servers')->andReturn($serversRelation); + + $preview = (new DeleteUserResources($this->user, true))->getResourcesPreview(); + + expect($preview['databases'])->toHaveCount(2); +}); + it('only collects resources from teams where user is the sole member', function () { // Mock owned team where user is the ONLY member (will be deleted) $ownedTeamPivot = (object) ['role' => 'owner'];