From f400c632f0f52737e94d4a904a425806ef216822 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sat, 15 Feb 2020 23:10:36 -0700 Subject: [PATCH] Update DeleteAccountPipeline, fixes #2016 --- app/Console/Commands/UserDelete.php | 26 +- .../DeletePipeline/DeleteAccountPipeline.php | 282 +++++++++--------- app/Observers/UserObserver.php | 4 + 3 files changed, 169 insertions(+), 143 deletions(-) diff --git a/app/Console/Commands/UserDelete.php b/app/Console/Commands/UserDelete.php index 8d03c8fde..258863e4e 100644 --- a/app/Console/Commands/UserDelete.php +++ b/app/Console/Commands/UserDelete.php @@ -13,7 +13,7 @@ class UserDelete extends Command * * @var string */ - protected $signature = 'user:delete {id}'; + protected $signature = 'user:delete {id} {--force}'; /** * The console command description. @@ -40,12 +40,24 @@ class UserDelete extends Command public function handle() { $id = $this->argument('id'); - $user = User::whereUsername($id)->orWhere('id', $id)->first(); + $force = $this->option('force'); + + if(ctype_digit($id) == true) { + $user = User::find($id); + } else { + $user = User::whereUsername($id)->first(); + } + if(!$user) { $this->error('Could not find any user with that username or id.'); exit; } + if($user->status == 'deleted' && $force == false) { + $this->error('Account has already been deleted.'); + return; + } + if($user->is_admin == true) { $this->error('Cannot delete an admin account from CLI.'); exit; @@ -62,10 +74,12 @@ class UserDelete extends Command exit; } - $profile = $user->profile; - $profile->status = $user->status = 'deleted'; - $profile->save(); - $user->save(); + if($user->status !== 'deleted') { + $profile = $user->profile; + $profile->status = $user->status = 'deleted'; + $profile->save(); + $user->save(); + } DeleteAccountPipeline::dispatch($user)->onQueue('high'); } diff --git a/app/Jobs/DeletePipeline/DeleteAccountPipeline.php b/app/Jobs/DeletePipeline/DeleteAccountPipeline.php index 735586576..c9777df5e 100644 --- a/app/Jobs/DeletePipeline/DeleteAccountPipeline.php +++ b/app/Jobs/DeletePipeline/DeleteAccountPipeline.php @@ -10,162 +10,170 @@ use Illuminate\Foundation\Bus\Dispatchable; use DB; use Illuminate\Support\Str; use App\{ - AccountLog, - Activity, - Avatar, - Bookmark, - Collection, - DirectMessage, - EmailVerification, - Follower, - FollowRequest, - Hashtag, - Like, - Media, - Mention, - Notification, - Profile, - Report, - ReportComment, - ReportLog, - StatusHashtag, - Status, - Story, - StoryView, - User, - UserDevice, - UserFilter, - UserSetting, + AccountLog, + Activity, + Avatar, + Bookmark, + Collection, + CollectionItem, + Contact, + DirectMessage, + EmailVerification, + Follower, + FollowRequest, + Hashtag, + HashtagFollow, + Like, + Media, + Mention, + Notification, + OauthClient, + Profile, + ProfileSponsor, + Report, + ReportComment, + ReportLog, + StatusHashtag, + Status, + Story, + StoryView, + User, + UserDevice, + UserFilter, + UserSetting, }; class DeleteAccountPipeline implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $user; + protected $user; - /** - * Create a new job instance. - * - * @return void - */ - public function __construct(User $user) - { - $this->user = $user; - } + public function __construct(User $user) + { + $this->user = $user; + } - /** - * Execute the job. - * - * @return void - */ - public function handle() - { - $user = $this->user; - DB::transaction(function() use ($user) { - AccountLog::chunk(200, function($logs) use ($user) { - foreach($logs as $log) { - if($log->user_id == $user->id) { - $log->forceDelete(); - } - } - }); - }); + public function handle() + { + $user = $this->user; - DB::transaction(function() use ($user) { - if($user->profile) { - $avatar = $user->profile->avatar; + DB::transaction(function() use ($user) { + AccountLog::chunk(200, function($logs) use ($user) { + foreach($logs as $log) { + if($log->user_id == $user->id) { + $log->forceDelete(); + } + } + }); + }); - $avatar->forceDelete(); - } + DB::transaction(function() use ($user) { + if($user->profile) { + $avatar = $user->profile->avatar; + $avatar->forceDelete(); + } - Bookmark::whereProfileId($user->profile->id)->forceDelete(); + $id = $user->profile_id; - EmailVerification::whereUserId($user->id)->forceDelete(); - $id = $user->profile->id; + Bookmark::whereProfileId($user->profile_id)->forceDelete(); + EmailVerification::whereUserId($user->id)->forceDelete(); + StatusHashtag::whereProfileId($id)->delete(); + FollowRequest::whereFollowingId($id) + ->orWhere('follower_id', $id) + ->forceDelete(); + Follower::whereProfileId($id) + ->orWhere('following_id', $id) + ->forceDelete(); + Like::whereProfileId($id)->forceDelete(); + }); - StatusHashtag::whereProfileId($id)->delete(); - - FollowRequest::whereFollowingId($id)->orWhere('follower_id', $id)->forceDelete(); + DB::transaction(function() use ($user) { + $pid = $this->user->profile_id; - Follower::whereProfileId($id)->orWhere('following_id', $id)->forceDelete(); + StoryView::whereProfileId($pid)->delete(); + $stories = Story::whereProfileId($pid)->get(); + foreach($stories as $story) { + $path = storage_path('app/'.$story->path); + if(is_file($path)) { + unlink($path); + } + $story->forceDelete(); + } + }); - Like::whereProfileId($id)->forceDelete(); - }); + DB::transaction(function() use ($user) { + $medias = Media::whereUserId($user->id)->get(); + foreach($medias as $media) { + $path = storage_path('app/'.$media->media_path); + $thumb = storage_path('app/'.$media->thumbnail_path); + if(is_file($path)) { + unlink($path); + } + if(is_file($thumb)) { + unlink($thumb); + } + $media->forceDelete(); + } + }); - DB::transaction(function() use ($user) { - $pid = $this->user->profile_id; + DB::transaction(function() use ($user) { + Mention::whereProfileId($user->profile_id)->forceDelete(); + Notification::whereProfileId($user->profile_id) + ->orWhere('actor_id', $user->profile_id) + ->forceDelete(); + }); - StoryView::whereProfileId($pid)->delete(); - $stories = Story::whereProfileId($pid)->get(); - foreach($stories as $story) { - $path = storage_path('app/'.$story->path); - if(is_file($path)) { - unlink($path); - } - $story->forceDelete(); - } - }); + DB::transaction(function() use ($user) { + $collections = Collection::whereProfileId($user->profile_id)->get(); + foreach ($collections as $collection) { + $collection->items()->delete(); + $collection->delete(); + } + Contact::whereUserId($user->id)->delete(); + HashtagFollow::whereUserId($user->id)->delete(); + OauthClient::whereUserId($user->id)->delete(); + ProfileSponsor::whereProfileId($user->profile_id)->delete(); + }); - DB::transaction(function() use ($user) { - $medias = Media::whereUserId($user->id)->get(); - foreach($medias as $media) { - $path = storage_path('app/'.$media->media_path); - $thumb = storage_path('app/'.$media->thumbnail_path); - if(is_file($path)) { - unlink($path); - } - if(is_file($thumb)) { - unlink($thumb); - } - $media->forceDelete(); - } - }); + DB::transaction(function() use ($user) { + Status::whereProfileId($user->profile_id)->forceDelete(); + Report::whereUserId($user->id)->forceDelete(); + $this->deleteProfile($user); + }); + } - DB::transaction(function() use ($user) { - Mention::whereProfileId($user->profile->id)->forceDelete(); - Notification::whereProfileId($user->profile->id)->orWhere('actor_id', $user->profile->id)->forceDelete(); - }); + protected function deleteProfile($user) { + DB::transaction(function() use ($user) { + Profile::whereUserId($user->id)->delete(); + $this->deleteUserSettings($user); + }); + } - DB::transaction(function() use ($user) { - Status::whereProfileId($user->profile->id)->forceDelete(); - Report::whereUserId($user->id)->forceDelete(); - $this->deleteProfile($user); - }); - } + protected function deleteUserSettings($user) { - protected function deleteProfile($user) { - DB::transaction(function() use ($user) { - Profile::whereUserId($user->id)->delete(); - $this->deleteUserSettings($user); - }); - } + DB::transaction(function() use ($user) { + UserDevice::whereUserId($user->id)->forceDelete(); + UserFilter::whereUserId($user->id)->forceDelete(); + UserSetting::whereUserId($user->id)->forceDelete(); + $this->deleteUserColumns($user); + }); + } - protected function deleteUserSettings($user) { - - DB::transaction(function() use ($user) { - UserDevice::whereUserId($user->id)->forceDelete(); - UserFilter::whereUserId($user->id)->forceDelete(); - UserSetting::whereUserId($user->id)->forceDelete(); - $this->deleteUserColumns($user); - }); - } - - protected function deleteUserColumns($user) - { - DB::transaction(function() use ($user) { - $user->status = 'deleted'; - $user->name = 'deleted'; - $user->email = $user->id; - $user->password = ''; - $user->remember_token = null; - $user->is_admin = false; - $user->{'2fa_enabled'} = false; - $user->{'2fa_secret'} = null; - $user->{'2fa_backup_codes'} = null; - $user->{'2fa_setup_at'} = null; - $user->save(); - }); - - } + protected function deleteUserColumns($user) + { + DB::transaction(function() use ($user) { + $user->status = 'deleted'; + $user->name = 'deleted'; + $user->email = $user->id; + $user->password = ''; + $user->remember_token = null; + $user->is_admin = false; + $user->{'2fa_enabled'} = false; + $user->{'2fa_secret'} = null; + $user->{'2fa_backup_codes'} = null; + $user->{'2fa_setup_at'} = null; + $user->save(); + }); + } } diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index db4b32b43..54398c62c 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -19,6 +19,10 @@ class UserObserver */ public function saved(User $user) { + if($user->status == 'deleted') { + return; + } + if (empty($user->profile)) { $profile = DB::transaction(function() use($user) { $profile = new Profile();