refactor(user): streamline user deletion process and enhance team management logic
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Livewire\Team;
|
namespace App\Livewire\Team;
|
||||||
|
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
use App\Models\Team;
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Hash;
|
use Illuminate\Support\Facades\Hash;
|
||||||
@@ -53,30 +52,12 @@ class AdminView extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function finalizeDeletion(User $user, Team $team)
|
|
||||||
{
|
|
||||||
$servers = $team->servers;
|
|
||||||
foreach ($servers as $server) {
|
|
||||||
$resources = $server->definedResources();
|
|
||||||
foreach ($resources as $resource) {
|
|
||||||
$resource->forceDelete();
|
|
||||||
}
|
|
||||||
$server->forceDelete();
|
|
||||||
}
|
|
||||||
|
|
||||||
$projects = $team->projects;
|
|
||||||
foreach ($projects as $project) {
|
|
||||||
$project->forceDelete();
|
|
||||||
}
|
|
||||||
$team->members()->detach($user->id);
|
|
||||||
$team->delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete($id, $password)
|
public function delete($id, $password)
|
||||||
{
|
{
|
||||||
if (! isInstanceAdmin()) {
|
if (! isInstanceAdmin()) {
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
|
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
|
||||||
if (! Hash::check($password, Auth::user()->password)) {
|
if (! Hash::check($password, Auth::user()->password)) {
|
||||||
$this->addError('password', 'The provided password is incorrect.');
|
$this->addError('password', 'The provided password is incorrect.');
|
||||||
@@ -84,52 +65,22 @@ class AdminView extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! auth()->user()->isInstanceAdmin()) {
|
if (! auth()->user()->isInstanceAdmin()) {
|
||||||
return $this->dispatch('error', 'You are not authorized to delete users');
|
return $this->dispatch('error', 'You are not authorized to delete users');
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = User::find($id);
|
$user = User::find($id);
|
||||||
$teams = $user->teams;
|
if (! $user) {
|
||||||
foreach ($teams as $team) {
|
return $this->dispatch('error', 'User not found');
|
||||||
$user_alone_in_team = $team->members->count() === 1;
|
|
||||||
if ($team->id === 0) {
|
|
||||||
if ($user_alone_in_team) {
|
|
||||||
return $this->dispatch('error', 'User is alone in the root team, cannot delete');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($user_alone_in_team) {
|
|
||||||
$this->finalizeDeletion($user, $team);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($user->isOwner()) {
|
|
||||||
$found_other_owner_or_admin = $team->members->filter(function ($member) {
|
|
||||||
return $member->pivot->role === 'owner' || $member->pivot->role === 'admin';
|
|
||||||
})->where('id', '!=', $user->id)->first();
|
|
||||||
|
|
||||||
if ($found_other_owner_or_admin) {
|
|
||||||
$team->members()->detach($user->id);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
$found_other_member_who_is_not_owner = $team->members->filter(function ($member) {
|
|
||||||
return $member->pivot->role === 'member';
|
|
||||||
})->first();
|
|
||||||
if ($found_other_member_who_is_not_owner) {
|
|
||||||
$found_other_member_who_is_not_owner->pivot->role = 'owner';
|
|
||||||
$found_other_member_who_is_not_owner->pivot->save();
|
|
||||||
$team->members()->detach($user->id);
|
|
||||||
} else {
|
|
||||||
$this->finalizeDeletion($user, $team);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
try {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$team->members()->detach($user->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$user->delete();
|
$user->delete();
|
||||||
$this->getUsers();
|
$this->getUsers();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->dispatch('error', $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ class Invitations extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$invitation = TeamInvitation::ownedByCurrentTeam()->findOrFail($invitation_id);
|
$invitation = TeamInvitation::ownedByCurrentTeam()->findOrFail($invitation_id);
|
||||||
$user = User::whereEmail($invitation->email)->firstOrFail();
|
$user = User::whereEmail($invitation->email)->first();
|
||||||
$emailVerified = $user->hasVerifiedEmail();
|
if (filled($user)) {
|
||||||
$forcePasswordReset = $user->force_password_reset;
|
$user->deleteIfNotVerifiedAndForcePasswordReset();
|
||||||
if ($emailVerified === false && $forcePasswordReset === true) {
|
|
||||||
$user->delete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$invitation->delete();
|
$invitation->delete();
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ class TeamInvitation extends Model
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
$this->delete();
|
$this->delete();
|
||||||
|
$user = User::whereEmail($this->email)->first();
|
||||||
|
if (filled($user)) {
|
||||||
|
$user->deleteIfNotVerifiedAndForcePasswordReset();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,92 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
$new_team = Team::create($team);
|
$new_team = Team::create($team);
|
||||||
$user->teams()->attach($new_team, ['role' => 'owner']);
|
$user->teams()->attach($new_team, ['role' => 'owner']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static::deleting(function (User $user) {
|
||||||
|
|
||||||
|
$teams = $user->teams;
|
||||||
|
foreach ($teams as $team) {
|
||||||
|
$user_alone_in_team = $team->members->count() === 1;
|
||||||
|
|
||||||
|
// Prevent deletion if user is alone in root team
|
||||||
|
if ($team->id === 0 && $user_alone_in_team) {
|
||||||
|
throw new \Exception('User is alone in the root team, cannot delete');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user_alone_in_team) {
|
||||||
|
static::finalizeTeamDeletion($user, $team);
|
||||||
|
// Delete any pending team invitations for this user
|
||||||
|
TeamInvitation::whereEmail($user->email)->delete();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the user's role for this team
|
||||||
|
$userRole = $team->members->where('id', $user->id)->first()?->pivot?->role;
|
||||||
|
|
||||||
|
if ($userRole === 'owner') {
|
||||||
|
$found_other_owner_or_admin = $team->members->filter(function ($member) use ($user) {
|
||||||
|
return ($member->pivot->role === 'owner' || $member->pivot->role === 'admin') && $member->id !== $user->id;
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($found_other_owner_or_admin) {
|
||||||
|
$team->members()->detach($user->id);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$found_other_member_who_is_not_owner = $team->members->filter(function ($member) {
|
||||||
|
return $member->pivot->role === 'member';
|
||||||
|
})->first();
|
||||||
|
|
||||||
|
if ($found_other_member_who_is_not_owner) {
|
||||||
|
$found_other_member_who_is_not_owner->pivot->role = 'owner';
|
||||||
|
$found_other_member_who_is_not_owner->pivot->save();
|
||||||
|
$team->members()->detach($user->id);
|
||||||
|
} else {
|
||||||
|
static::finalizeTeamDeletion($user, $team);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$team->members()->detach($user->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize team deletion by cleaning up all associated resources
|
||||||
|
*/
|
||||||
|
private static function finalizeTeamDeletion(User $user, Team $team)
|
||||||
|
{
|
||||||
|
$servers = $team->servers;
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
$resources = $server->definedResources();
|
||||||
|
foreach ($resources as $resource) {
|
||||||
|
$resource->forceDelete();
|
||||||
|
}
|
||||||
|
$server->forceDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$projects = $team->projects;
|
||||||
|
foreach ($projects as $project) {
|
||||||
|
$project->forceDelete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$team->members()->detach($user->id);
|
||||||
|
$team->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the user if they are not verified and have a force password reset.
|
||||||
|
* This is used to clean up users that have been invited, does not accepted the invitation (and did not verify their email and have a force password reset).
|
||||||
|
*/
|
||||||
|
public function deleteIfNotVerifiedAndForcePasswordReset()
|
||||||
|
{
|
||||||
|
if ($this->hasVerifiedEmail() === false && $this->force_password_reset === true) {
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function recreate_personal_team()
|
public function recreate_personal_team()
|
||||||
|
|||||||
Reference in New Issue
Block a user