diff --git a/app/Console/Commands/FixDuplicateProfiles.php b/app/Console/Commands/FixDuplicateProfiles.php index d74887d27..8a0e3272e 100644 --- a/app/Console/Commands/FixDuplicateProfiles.php +++ b/app/Console/Commands/FixDuplicateProfiles.php @@ -5,12 +5,36 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use App\{ + Avatar, + Bookmark, + Collection, + DirectMessage, + FollowRequest, + Follower, + HashtagFollow, Like, Media, + MediaTag, + Mention, Profile, + Report, + ReportComment, + ReportLog, + StatusArchived, + StatusHashtag, + StatusView, Status, - User + Story, + StoryView, + User, + UserFilter }; +use App\Models\{ + Conversation, + Portfolio, + UserPronoun +}; +use DB, Cache; class FixDuplicateProfiles extends Command { @@ -45,31 +69,174 @@ class FixDuplicateProfiles extends Command */ public function handle() { - $profiles = Profile::selectRaw('count(user_id) as count,user_id')->whereNotNull('user_id')->groupBy('user_id')->orderBy('user_id', 'desc')->get()->where('count', '>', 1); - $count = $profiles->count(); - if($count == 0) { - $this->info("No duplicate profiles found!"); - return; - } - $this->info("Found {$count} accounts with duplicate profiles..."); - $bar = $this->output->createProgressBar($count); - $bar->start(); + $duplicates = DB::table('profiles') + ->whereNull('domain') + ->select('username', DB::raw('COUNT(*) as `count`')) + ->groupBy('username') + ->havingRaw('COUNT(*) > 1') + ->pluck('username'); - foreach ($profiles as $profile) { - $dup = Profile::whereUserId($profile->user_id)->get(); - - if( - $dup->first()->username === $dup->last()->username && - $dup->last()->statuses()->count() == 0 && - $dup->last()->followers()->count() == 0 && - $dup->last()->likes()->count() == 0 && - $dup->last()->media()->count() == 0 - ) { - $dup->last()->avatar->forceDelete(); - $dup->last()->forceDelete(); + foreach($duplicates as $dupe) { + $ids = Profile::whereNull('domain')->whereUsername($dupe)->pluck('id'); + if(!$ids || $ids->count() != 2) { + continue; } - $bar->advance(); + $id = $ids->first(); + $oid = $ids->last(); + + $user = User::whereUsername($dupe)->first(); + if($user) { + $user->profile_id = $id; + $user->save(); + } else { + continue; + } + + $this->checkAvatar($id, $oid); + $this->checkBookmarks($id, $oid); + $this->checkCollections($id, $oid); + $this->checkConversations($id, $oid); + $this->checkDirectMessages($id, $oid); + $this->checkFollowRequest($id, $oid); + $this->checkFollowers($id, $oid); + $this->checkHashtagFollow($id, $oid); + $this->checkLikes($id, $oid); + $this->checkMedia($id, $oid); + $this->checkMediaTag($id, $oid); + $this->checkMention($id, $oid); + $this->checkPortfolio($id, $oid); + $this->checkReport($id, $oid); + $this->checkStatusArchived($id, $oid); + $this->checkStatusHashtag($id, $oid); + $this->checkStatusView($id, $oid); + $this->checkStatus($id, $oid); + $this->checkStory($id, $oid); + $this->checkStoryView($id, $oid); + $this->checkUserFilter($id, $oid); + $this->checkUserPronoun($id, $oid); + Profile::find($oid)->forceDelete(); } - $bar->finish(); + + Cache::clear(); } + + protected function checkAvatar($id, $oid) + { + Avatar::whereProfileId($oid)->forceDelete(); + } + + protected function checkBookmarks($id, $oid) + { + Bookmark::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkCollections($id, $oid) + { + Collection::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkConversations($id, $oid) + { + Conversation::whereToId($oid)->update(['to_id' => $id]); + Conversation::whereFromId($oid)->update(['from_id' => $id]); + } + + protected function checkDirectMessages($id, $oid) + { + DirectMessage::whereToId($oid)->update(['to_id' => $id]); + DirectMessage::whereFromId($oid)->update(['from_id' => $id]); + } + + protected function checkFollowRequest($id, $oid) + { + FollowRequest::whereFollowerId($oid)->update(['follower_id' => $id]); + FollowRequest::whereFollowingId($oid)->update(['following_id' => $id]); + } + + protected function checkFollowers($id, $oid) + { + Follower::whereProfileId($oid)->update(['profile_id' => $id]); + Follower::whereFollowingId($oid)->update(['following_id' => $id]); + } + + protected function checkHashtagFollow($id, $oid) + { + HashtagFollow::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkLikes($id, $oid) + { + Like::whereStatusProfileId($oid)->update(['status_profile_id' => $id]); + Like::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkMedia($id, $oid) + { + Media::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkMediaTag($id, $oid) + { + MediaTag::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkMention($id, $oid) + { + Mention::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkPortfolio($id, $oid) + { + Portfolio::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkReport($id, $oid) + { + ReportComment::whereProfileId($oid)->update(['profile_id' => $id]); + ReportLog::whereProfileId($oid)->update(['profile_id' => $id]); + Report::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStatusArchived($id, $oid) + { + StatusArchived::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStatusHashtag($id, $oid) + { + StatusHashtag::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStatusView($id, $oid) + { + StatusView::whereStatusProfileId($oid)->update(['profile_id' => $id]); + StatusView::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStatus($id, $oid) + { + Status::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStory($id, $oid) + { + Story::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkStoryView($id, $oid) + { + StoryView::whereProfileId($oid)->update(['profile_id' => $id]); + } + + protected function checkUserFilter($id, $oid) + { + UserFilter::whereUserId($oid)->update(['user_id' => $id]); + UserFilter::whereFilterableType('App\Profile')->whereFilterableId($oid)->update(['filterable_id' => $id]); + } + + protected function checkUserPronoun($id, $oid) + { + UserPronoun::whereProfileId($oid)->update(['profile_id' => $id]); + } + } diff --git a/app/Like.php b/app/Like.php index 678ce953f..00af1030a 100644 --- a/app/Like.php +++ b/app/Like.php @@ -17,7 +17,7 @@ class Like extends Model * @var array */ protected $dates = ['deleted_at']; - protected $fillable = ['profile_id', 'status_id']; + protected $fillable = ['profile_id', 'status_id', 'status_profile_id']; public function actor() { diff --git a/app/Media.php b/app/Media.php index 6a25a5643..3e9afe1ed 100644 --- a/app/Media.php +++ b/app/Media.php @@ -19,6 +19,8 @@ class Media extends Model */ protected $dates = ['deleted_at']; + protected $guarded = []; + protected $casts = [ 'srcset' => 'array' ]; diff --git a/app/MediaTag.php b/app/MediaTag.php index ff5fe9b6e..49dd52b16 100644 --- a/app/MediaTag.php +++ b/app/MediaTag.php @@ -6,6 +6,8 @@ use Illuminate\Database\Eloquent\Model; class MediaTag extends Model { + protected $guarded = []; + public function status() { return $this->belongsTo(Status::class); diff --git a/app/Mention.php b/app/Mention.php index 25c91ff11..d39399fcb 100644 --- a/app/Mention.php +++ b/app/Mention.php @@ -16,6 +16,8 @@ class Mention extends Model */ protected $dates = ['deleted_at']; + protected $guarded = []; + public function profile() { return $this->belongsTo(Profile::class, 'profile_id', 'id'); diff --git a/app/Models/Conversation.php b/app/Models/Conversation.php index 4f541a097..5b06c1c01 100644 --- a/app/Models/Conversation.php +++ b/app/Models/Conversation.php @@ -8,4 +8,6 @@ use Illuminate\Database\Eloquent\Model; class Conversation extends Model { use HasFactory; + + protected $fillable = ['from_id', 'to_id']; } diff --git a/app/Models/Portfolio.php b/app/Models/Portfolio.php index 758e8db49..56f3afd88 100644 --- a/app/Models/Portfolio.php +++ b/app/Models/Portfolio.php @@ -11,6 +11,7 @@ class Portfolio extends Model use HasFactory; public $fillable = [ + 'profile_id', 'active', 'show_captions', 'show_license', diff --git a/app/Models/UserPronoun.php b/app/Models/UserPronoun.php index 9fbf77d79..9fe7bb5b0 100644 --- a/app/Models/UserPronoun.php +++ b/app/Models/UserPronoun.php @@ -8,4 +8,6 @@ use Illuminate\Database\Eloquent\Model; class UserPronoun extends Model { use HasFactory; + + protected $guarded = []; } diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php index 7b41d27f7..ec4ef9f34 100644 --- a/app/Observers/UserObserver.php +++ b/app/Observers/UserObserver.php @@ -26,6 +26,10 @@ class UserObserver return; } + if(Profile::whereUsername($user->username)->exists()) { + return; + } + if (empty($user->profile)) { $profile = DB::transaction(function() use($user) { $profile = new Profile(); diff --git a/app/Report.php b/app/Report.php index 0aadc4616..bafde0b4d 100644 --- a/app/Report.php +++ b/app/Report.php @@ -8,6 +8,8 @@ class Report extends Model { protected $dates = ['admin_seen']; + protected $guarded = []; + public function url() { return url('/i/admin/reports/show/'.$this->id); diff --git a/app/ReportComment.php b/app/ReportComment.php index 1e57c49ce..070a7117c 100644 --- a/app/ReportComment.php +++ b/app/ReportComment.php @@ -6,6 +6,8 @@ use Illuminate\Database\Eloquent\Model; class ReportComment extends Model { + protected $guarded = []; + public function profile() { return $this->belongsTo(Profile::class); diff --git a/app/ReportLog.php b/app/ReportLog.php index eaa842e97..18080da6d 100644 --- a/app/ReportLog.php +++ b/app/ReportLog.php @@ -6,6 +6,8 @@ use Illuminate\Database\Eloquent\Model; class ReportLog extends Model { + protected $guarded = []; + public function profile() { return $this->belongsTo(Profile::class); diff --git a/app/StatusArchived.php b/app/StatusArchived.php index 862dddc69..a56a09cbd 100644 --- a/app/StatusArchived.php +++ b/app/StatusArchived.php @@ -8,4 +8,6 @@ use Illuminate\Database\Eloquent\Model; class StatusArchived extends Model { use HasFactory; + + protected $guarded = []; } diff --git a/database/migrations/2023_01_21_124608_fix_duplicate_profiles.php b/database/migrations/2023_01_21_124608_fix_duplicate_profiles.php new file mode 100644 index 000000000..12c8b82e5 --- /dev/null +++ b/database/migrations/2023_01_21_124608_fix_duplicate_profiles.php @@ -0,0 +1,29 @@ +