diff --git a/app/Jobs/DeletePipeline/DeleteAccountPipeline.php b/app/Jobs/DeletePipeline/DeleteAccountPipeline.php index 6b188aa8d..b7e41fed8 100644 --- a/app/Jobs/DeletePipeline/DeleteAccountPipeline.php +++ b/app/Jobs/DeletePipeline/DeleteAccountPipeline.php @@ -50,6 +50,10 @@ use App\{ UserFilter, UserSetting, }; +use App\Models\Conversation; +use App\Models\Poll; +use App\Models\PollVote; +use App\Models\Portfolio; use App\Models\UserPronoun; class DeleteAccountPipeline implements ShouldQueue @@ -59,6 +63,9 @@ class DeleteAccountPipeline implements ShouldQueue protected $user; public $timeout = 900; + public $tries = 3; + public $maxExceptions = 1; + public $deleteWhenMissingModels = true; public function __construct(User $user) { @@ -68,160 +75,108 @@ class DeleteAccountPipeline implements ShouldQueue public function handle() { $user = $this->user; + $profile = $user->profile; + $id = $user->profile_id; $this->deleteUserColumns($user); AccountService::del($user->profile_id); - DB::transaction(function() use ($user) { - AccountLog::whereItemType('App\User')->whereItemId($user->id)->forceDelete(); - }); + AccountLog::whereItemType('App\User')->whereItemId($user->id)->forceDelete(); - DB::transaction(function() use ($user) { - AccountInterstitial::whereUserId($user->id)->delete(); - }); + AccountInterstitial::whereUserId($user->id)->delete(); - DB::transaction(function() use ($user) { - if($user->profile) { - $avatar = $user->profile->avatar; - $path = $avatar->media_path; - if(!in_array($path, [ - 'public/avatars/default.jpg', - 'public/avatars/default.png' - ])) { - if(config('pixelfed.cloud_storage')) { - $disk = Storage::disk(config('filesystems.cloud')); - if($disk->exists($path)) { - $disk->delete($path); - } - } - $disk = Storage::disk(config('filesystems.local')); - if($disk->exists($path)) { - $disk->delete($path); - } - } + // Delete Avatar + $profile->avatar->forceDelete(); - $avatar->forceDelete(); - } + // Delete Poll Votes + PollVote::whereProfileId($id)->delete(); - $id = $user->profile_id; + // Delete Polls + Poll::whereProfileId($id)->delete(); - ImportData::whereProfileId($id) - ->cursor() - ->each(function($data) { - $path = storage_path('app/'.$data->path); - if(is_file($path)) { - unlink($path); - } - $data->delete(); - }); - ImportJob::whereProfileId($id) - ->cursor() - ->each(function($data) { - $path = storage_path('app/'.$data->media_json); - if(is_file($path)) { - unlink($path); - } - $data->delete(); - }); - MediaTag::whereProfileId($id)->delete(); - Bookmark::whereProfileId($id)->forceDelete(); - EmailVerification::whereUserId($user->id)->forceDelete(); - StatusHashtag::whereProfileId($id)->delete(); - DirectMessage::whereFromId($id)->orWhere('to_id', $id)->delete(); - StatusArchived::whereProfileId($id)->delete(); - UserPronoun::whereProfileId($id)->delete(); - FollowRequest::whereFollowingId($id) - ->orWhere('follower_id', $id) - ->forceDelete(); - Follower::whereProfileId($id) - ->orWhere('following_id', $id) - ->each(function($follow) { - FollowerService::remove($follow->profile_id, $follow->following_id); - $follow->delete(); - }); - FollowerService::delCache($id); - Like::whereProfileId($id)->forceDelete(); - }); + // Delete Portfolio + Portfolio::whereProfileId($id)->delete(); - DB::transaction(function() use ($user) { - $pid = $this->user->profile_id; - - StoryView::whereProfileId($pid)->delete(); - $stories = Story::whereProfileId($pid)->get(); - foreach($stories as $story) { - $path = storage_path('app/'.$story->path); + ImportData::whereProfileId($id) + ->cursor() + ->each(function($data) { + $path = storage_path('app/'.$data->path); if(is_file($path)) { unlink($path); } - $story->forceDelete(); - } + $data->delete(); }); - DB::transaction(function() use ($user) { - $medias = Media::whereUserId($user->id)->get(); - foreach($medias as $media) { - if(config('pixelfed.cloud_storage')) { - $disk = Storage::disk(config('filesystems.cloud')); - if($disk->exists($media->media_path)) { - $disk->delete($media->media_path); - } - if($disk->exists($media->thumbnail_path)) { - $disk->delete($media->thumbnail_path); - } + ImportJob::whereProfileId($id) + ->cursor() + ->each(function($data) { + $path = storage_path('app/'.$data->media_json); + if(is_file($path)) { + unlink($path); } - $disk = Storage::disk(config('filesystems.local')); - if($disk->exists($media->media_path)) { - $disk->delete($media->media_path); - } - if($disk->exists($media->thumbnail_path)) { - $disk->delete($media->thumbnail_path); - } - $media->forceDelete(); + $data->delete(); + }); + + MediaTag::whereProfileId($id)->delete(); + Bookmark::whereProfileId($id)->forceDelete(); + EmailVerification::whereUserId($user->id)->forceDelete(); + StatusHashtag::whereProfileId($id)->delete(); + DirectMessage::whereFromId($id)->orWhere('to_id', $id)->delete(); + Conversation::whereFromId($id)->orWhere('to_id', $id)->delete(); + StatusArchived::whereProfileId($id)->delete(); + UserPronoun::whereProfileId($id)->delete(); + FollowRequest::whereFollowingId($id) + ->orWhere('follower_id', $id) + ->forceDelete(); + Follower::whereProfileId($id) + ->orWhere('following_id', $id) + ->each(function($follow) { + FollowerService::remove($follow->profile_id, $follow->following_id); + $follow->delete(); + }); + FollowerService::delCache($id); + Like::whereProfileId($id)->forceDelete(); + Mention::whereProfileId($id)->forceDelete(); + + StoryView::whereProfileId($id)->delete(); + $stories = Story::whereProfileId($id)->get(); + foreach($stories as $story) { + $path = storage_path('app/'.$story->path); + if(is_file($path)) { + unlink($path); } - }); + $story->forceDelete(); + } - DB::transaction(function() use ($user) { - Mention::whereProfileId($user->profile_id)->forceDelete(); - Notification::whereProfileId($user->profile_id) - ->orWhere('actor_id', $user->profile_id) - ->forceDelete(); - }); + UserDevice::whereUserId($user->id)->forceDelete(); + UserFilter::whereUserId($user->id)->forceDelete(); + UserSetting::whereUserId($user->id)->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(); - DB::table('oauth_access_tokens')->whereUserId($user->id)->delete(); - DB::table('oauth_auth_codes')->whereUserId($user->id)->delete(); - ProfileSponsor::whereProfileId($user->profile_id)->delete(); - }); + Mention::whereProfileId($id)->forceDelete(); + Notification::whereProfileId($id) + ->orWhere('actor_id', $id) + ->forceDelete(); - DB::transaction(function() use ($user) { - Status::whereProfileId($user->profile_id)->forceDelete(); - Report::whereUserId($user->id)->forceDelete(); - PublicTimelineService::warmCache(true, 400); - $this->deleteProfile($user); - }); - } + $collections = Collection::whereProfileId($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(); + DB::table('oauth_access_tokens')->whereUserId($user->id)->delete(); + DB::table('oauth_auth_codes')->whereUserId($user->id)->delete(); + ProfileSponsor::whereProfileId($id)->delete(); - protected function deleteProfile($user) { - DB::transaction(function() use ($user) { - Profile::whereUserId($user->id)->delete(); - $this->deleteUserSettings($user); - }); - } + Status::whereProfileId($id)->chunk(50, function($statuses) { + foreach($statuses as $status) { + StatusDelete::dispatch($status)->onQueue('high'); + } + }); - protected function deleteUserSettings($user) { - - DB::transaction(function() use ($user) { - UserDevice::whereUserId($user->id)->forceDelete(); - UserFilter::whereUserId($user->id)->forceDelete(); - UserSetting::whereUserId($user->id)->forceDelete(); - }); + Report::whereUserId($user->id)->forceDelete(); + PublicTimelineService::warmCache(true, 400); + Profile::whereUserId($user->id)->delete(); } protected function deleteUserColumns($user) diff --git a/app/Jobs/DeletePipeline/DeleteRemoteProfilePipeline.php b/app/Jobs/DeletePipeline/DeleteRemoteProfilePipeline.php index 5c3cb3fe6..430bace79 100644 --- a/app/Jobs/DeletePipeline/DeleteRemoteProfilePipeline.php +++ b/app/Jobs/DeletePipeline/DeleteRemoteProfilePipeline.php @@ -39,6 +39,7 @@ use App\{ ReportLog, StatusHashtag, Status, + StatusView, Story, StoryView, User, @@ -46,6 +47,10 @@ use App\{ UserFilter, UserSetting, }; +use App\Models\Conversation; +use App\Models\Poll; +use App\Models\PollVote; +use App\Services\AccountService; class DeleteRemoteProfilePipeline implements ShouldQueue { @@ -53,6 +58,11 @@ class DeleteRemoteProfilePipeline implements ShouldQueue protected $profile; + public $timeout = 900; + public $tries = 3; + public $maxExceptions = 1; + public $deleteWhenMissingModels = true; + public function __construct(Profile $profile) { $this->profile = $profile; @@ -61,80 +71,85 @@ class DeleteRemoteProfilePipeline implements ShouldQueue public function handle() { $profile = $this->profile; + $pid = $profile->id; if($profile->domain == null || $profile->private_key) { return; } - DB::transaction(function() use ($profile) { - $profile->avatar->forceDelete(); + $profile->status = 'delete'; + $profile->save(); - $id = $profile->id; + AccountService::del($pid); - MediaTag::whereProfileId($id)->delete(); - StatusHashtag::whereProfileId($id)->delete(); - DirectMessage::whereFromId($id)->delete(); - FollowRequest::whereFollowingId($id) - ->orWhere('follower_id', $id) - ->forceDelete(); - Follower::whereProfileId($id) - ->orWhere('following_id', $id) - ->forceDelete(); - Like::whereProfileId($id)->forceDelete(); + // Delete statuses + Status::whereProfileId($pid) + ->chunk(50, function($statuses) { + foreach($statuses as $status) { + DeleteRemoteStatusPipeline::dispatch($status)->onQueue('delete'); + } }); - DB::transaction(function() use ($profile) { - $pid = $profile->id; - 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(); + // Delete Poll Votes + PollVote::whereProfileId($pid)->delete(); + + // Delete Polls + Poll::whereProfileId($pid)->delete(); + + // Delete Avatar + $profile->avatar->forceDelete(); + + // Delete media tags + MediaTag::whereProfileId($pid)->delete(); + + // Delete DMs + DirectMessage::whereFromId($pid)->orWhere('to_id', $pid)->delete(); + Conversation::whereFromId($pid)->orWhere('to_id', $pid)->delete(); + + // Delete FollowRequests + FollowRequest::whereFollowingId($pid) + ->orWhere('follower_id', $pid) + ->delete(); + + // Delete relationships + Follower::whereProfileId($pid) + ->orWhere('following_id', $pid) + ->delete(); + + // Delete likes + Like::whereProfileId($pid)->forceDelete(); + + // Delete Story Views + Stories + 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 ($profile) { - $medias = Media::whereProfileId($profile->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); + // Delete mutes/blocks + UserFilter::whereFilterableType('App\Profile')->whereFilterableId($pid)->delete(); + + // Delete mentions + Mention::whereProfileId($pid)->forceDelete(); + + // Delete notifications + Notification::whereProfileId($pid) + ->orWhere('actor_id', $pid) + ->chunk(50, function($notifications) { + foreach($notifications as $n) { + $n->forceDelete(); } - if(is_file($thumb)) { - unlink($thumb); - } - $media->forceDelete(); - } - }); + }); - DB::transaction(function() use ($profile) { - Mention::whereProfileId($profile->id)->forceDelete(); - Notification::whereProfileId($profile->id) - ->orWhere('actor_id', $profile->id) - ->forceDelete(); - }); + // Delete reports + Report::whereProfileId($profile->id)->orWhere('reported_profile_id')->forceDelete(); - DB::transaction(function() use ($profile) { - Status::whereProfileId($profile->id) - ->cursor() - ->each(function($status) { - AccountInterstitial::where('item_type', 'App\Status') - ->where('item_id', $status->id) - ->delete(); - $status->forceDelete(); - }); - Report::whereProfileId($profile->id)->forceDelete(); - $this->deleteProfile($profile); - }); - } - - protected function deleteProfile($profile) { - DB::transaction(function() use ($profile) { - Profile::findOrFail($profile->id)->delete(); - }); + // Delete profile + Profile::findOrFail($profile->id)->delete(); + return; } } diff --git a/app/Jobs/DeletePipeline/DeleteRemoteStatusPipeline.php b/app/Jobs/DeletePipeline/DeleteRemoteStatusPipeline.php index ccab18415..8a692ebc7 100644 --- a/app/Jobs/DeletePipeline/DeleteRemoteStatusPipeline.php +++ b/app/Jobs/DeletePipeline/DeleteRemoteStatusPipeline.php @@ -19,10 +19,12 @@ use App\Status; use App\StatusHashtag; use App\StatusView; use App\Notification; +use App\Services\AccountService; use App\Services\NetworkTimelineService; use App\Services\StatusService; use App\Jobs\ProfilePipeline\DecrementPostCount; use App\Jobs\MediaPipeline\MediaDeletePipeline; +use Cache; class DeleteRemoteStatusPipeline implements ShouldQueue { @@ -30,9 +32,10 @@ class DeleteRemoteStatusPipeline implements ShouldQueue protected $status; - public $timeout = 300; - public $tries = 3; + public $timeout = 30; + public $tries = 2; public $maxExceptions = 1; + public $deleteWhenMissingModels = true; /** * Create a new job instance. @@ -41,7 +44,7 @@ class DeleteRemoteStatusPipeline implements ShouldQueue */ public function __construct(Status $status) { - $this->status = $status->withoutRelations(); + $this->status = $status; } /** @@ -53,9 +56,12 @@ class DeleteRemoteStatusPipeline implements ShouldQueue { $status = $this->status; + if(AccountService::get($status->profile_id, true)) { + DecrementPostCount::dispatch($status->profile_id)->onQueue('feed'); + } + NetworkTimelineService::del($status->id); - StatusService::del($status->id, true); - DecrementPostCount::dispatchNow($status->profile_id); + Cache::forget(StatusService::key($status->id)); Bookmark::whereStatusId($status->id)->delete(); Notification::whereItemType('App\Status') ->whereItemId($status->id) @@ -73,6 +79,7 @@ class DeleteRemoteStatusPipeline implements ShouldQueue StatusHashtag::whereStatusId($status->id)->delete(); StatusView::whereStatusId($status->id)->delete(); Status::whereReblogOfId($status->id)->forceDelete(); - $status->delete(); + $status->forceDelete(); + return 1; } } diff --git a/app/Jobs/MediaPipeline/MediaDeletePipeline.php b/app/Jobs/MediaPipeline/MediaDeletePipeline.php index 6afba1701..4fb8427c7 100644 --- a/app/Jobs/MediaPipeline/MediaDeletePipeline.php +++ b/app/Jobs/MediaPipeline/MediaDeletePipeline.php @@ -20,6 +20,7 @@ class MediaDeletePipeline implements ShouldQueue public $timeout = 300; public $tries = 3; public $maxExceptions = 1; + public $deleteWhenMissingModels = true; public function __construct(Media $media) { @@ -40,32 +41,27 @@ class MediaDeletePipeline implements ShouldQueue array_pop($e); $i = implode('/', $e); - if(config_cache('pixelfed.cloud_storage') == true) { + if(config('pixelfed.cloud_storage') == true) { $disk = Storage::disk(config('filesystems.cloud')); - if($path) { + if($path && $disk->exists($path)) { $disk->delete($path); } - if($thumb) { + if($thumb && $disk->exists($thumb)) { $disk->delete($thumb); } - - if(count($e) > 4 && count($disk->files($i)) == 0) { - $disk->deleteDirectory($i); - } } $disk = Storage::disk(config('filesystems.local')); + if($path && $disk->exists($path)) { $disk->delete($path); } + if($thumb && $disk->exists($thumb)) { $disk->delete($thumb); } - if(count($e) > 4 && count($disk->files($i)) == 0) { - $disk->deleteDirectory($i); - } $media->forceDelete(); diff --git a/app/Jobs/MediaPipeline/MediaStoragePipeline.php b/app/Jobs/MediaPipeline/MediaStoragePipeline.php index 61f80767c..90b6c181b 100644 --- a/app/Jobs/MediaPipeline/MediaStoragePipeline.php +++ b/app/Jobs/MediaPipeline/MediaStoragePipeline.php @@ -17,6 +17,7 @@ class MediaStoragePipeline implements ShouldQueue use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $media; + public $deleteWhenMissingModels = true; public function __construct(Media $media) { @@ -28,4 +29,4 @@ class MediaStoragePipeline implements ShouldQueue MediaStorageService::store($this->media); } -} \ No newline at end of file +} diff --git a/app/Jobs/StatusPipeline/StatusDelete.php b/app/Jobs/StatusPipeline/StatusDelete.php index 4f395a520..deee089d8 100644 --- a/app/Jobs/StatusPipeline/StatusDelete.php +++ b/app/Jobs/StatusPipeline/StatusDelete.php @@ -89,7 +89,7 @@ class StatusDelete implements ShouldQueue Media::whereStatusId($status->id) ->get() ->each(function($media) { - MediaDeletePipeline::dispatchNow($media); + MediaDeletePipeline::dispatch($media)->onQueue('mmo'); }); if($status->in_reply_to_id) { diff --git a/app/Observers/AvatarObserver.php b/app/Observers/AvatarObserver.php index 6c644099e..b7854e66f 100644 --- a/app/Observers/AvatarObserver.php +++ b/app/Observers/AvatarObserver.php @@ -65,7 +65,7 @@ class AvatarObserver @unlink($path); } - if($avatar->cdn_url && config_cache('pixelfed.cloud_storage')) { + if(config_cache('pixelfed.cloud_storage')) { $disk = Storage::disk(config('filesystems.cloud')); $base = Str::startsWith($avatar->media_path, 'cache/avatars/'); if($base && $disk->exists($avatar->media_path)) { diff --git a/app/Services/MediaStorageService.php b/app/Services/MediaStorageService.php index f7be84fff..99a087f6b 100644 --- a/app/Services/MediaStorageService.php +++ b/app/Services/MediaStorageService.php @@ -274,6 +274,6 @@ class MediaStorageService { if(!$confirm) { return; } - MediaDeletePipeline::dispatch($media); + MediaDeletePipeline::dispatch($media)->onQueue('mmo'); } }