Browse Source

Update AdminApiController, improve admin moderation tools

Daniel Supernault 2 years ago
parent
commit
763ce19a0a

+ 145 - 5
app/Http/Controllers/Api/AdminApiController.php

@@ -27,10 +27,14 @@ use App\Services\InstanceService;
 use App\Services\ModLogService;
 use App\Services\SnowflakeService;
 use App\Services\StatusService;
+use App\Services\PublicTimelineService;
 use App\Services\NetworkTimelineService;
 use App\Services\NotificationService;
 use App\Http\Resources\AdminInstance;
 use App\Http\Resources\AdminUser;
+use App\Jobs\DeletePipeline\DeleteAccountPipeline;
+use App\Jobs\DeletePipeline\DeleteRemoteProfilePipeline;
+use App\Jobs\DeletePipeline\DeleteRemoteStatusPipeline;
 
 class AdminApiController extends Controller
 {
@@ -95,7 +99,7 @@ class AdminApiController extends Controller
         abort_unless($request->user()->is_admin == 1, 404);
 
         $this->validate($request, [
-            'action' => 'required|in:dismiss,approve,dismiss-all,approve-all',
+            'action' => 'required|in:dismiss,approve,dismiss-all,approve-all,delete-post,delete-account',
             'id' => 'required'
         ]);
 
@@ -107,14 +111,53 @@ class AdminApiController extends Controller
         $now = now();
         $res = ['status' => 'success'];
         $meta = json_decode($appeal->meta);
+        $user = $appeal->user;
+        $profile = $user->profile;
 
         if($action == 'dismiss') {
             $appeal->is_spam = true;
             $appeal->appeal_handled_at = $now;
             $appeal->save();
 
-            Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $appeal->user->profile_id);
-            Cache::forget('pf:bouncer_v0:recent_by_pid:' . $appeal->user->profile_id);
+            Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $profile->id);
+            Cache::forget('pf:bouncer_v0:recent_by_pid:' . $profile->id);
+            Cache::forget('admin-dash:reports:spam-count');
+            return $res;
+        }
+
+        if($action == 'delete-post') {
+            $appeal->appeal_handled_at = now();
+            $appeal->is_spam = true;
+            $appeal->save();
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($appeal->status->id)
+                ->objectType('App\Status::class')
+                ->user($request->user())
+                ->action('admin.status.delete')
+                ->accessLevel('admin')
+                ->save();
+            PublicTimelineService::deleteByProfileId($profile->id);
+            StatusDelete::dispatch($appeal->status)->onQueue('high');
+            Cache::forget('admin-dash:reports:spam-count');
+            return $res;
+        }
+
+        if($action == 'delete-account') {
+            abort_if($user->is_admin, 400, 'Cannot delete an admin account.');
+            $appeal->appeal_handled_at = now();
+            $appeal->is_spam = true;
+            $appeal->save();
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($profile->id)
+                ->objectType('App\User::class')
+                ->user($request->user())
+                ->action('admin.user.delete')
+                ->accessLevel('admin')
+                ->save();
+            PublicTimelineService::deleteByProfileId($profile->id);
+            DeleteAccountPipeline::dispatch($appeal->user)->onQueue('high');
             Cache::forget('admin-dash:reports:spam-count');
             return $res;
         }
@@ -459,7 +502,7 @@ class AdminApiController extends Controller
 
         $this->validate($request, [
             'id' => 'required',
-            'action' => 'required|in:unlisted,cw,no_autolink,refresh_stats,verify_email',
+            'action' => 'required|in:unlisted,cw,no_autolink,refresh_stats,verify_email,delete',
             'value' => 'sometimes'
         ]);
 
@@ -470,7 +513,59 @@ class AdminApiController extends Controller
 
         abort_if($user->is_admin == true && $action !== 'refresh_stats', 400, 'Cannot moderate admin accounts');
 
-        if($action === 'refresh_stats') {
+        if($action === 'delete') {
+            if(config('pixelfed.account_deletion') == false) {
+                abort(404);
+            }
+
+            abort_if($user->is_admin, 400, 'Cannot delete an admin account.');
+
+            $ts = now()->addMonth();
+
+            $user->status = 'delete';
+            $user->delete_after = $ts;
+            $user->save();
+
+            $profile->status = 'delete';
+            $profile->delete_after = $ts;
+            $profile->save();
+
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($profile->id)
+                ->objectType('App\Profile::class')
+                ->user($request->user())
+                ->action('admin.user.delete')
+                ->accessLevel('admin')
+                ->save();
+
+            PublicTimelineService::deleteByProfileId($profile->id);
+            NetworkTimelineService::deleteByProfileId($profile->id);
+
+            if($profile->user_id) {
+                DB::table('oauth_access_tokens')->whereUserId($user->id)->delete();
+                DB::table('oauth_auth_codes')->whereUserId($user->id)->delete();
+                $user->email = $user->id;
+                $user->password = '';
+                $user->status = 'delete';
+                $user->save();
+                $profile->status = 'delete';
+                $profile->delete_after = now()->addMonth();
+                $profile->save();
+                AccountService::del($profile->id);
+                DeleteAccountPipeline::dispatch($user)->onQueue('high');
+            } else {
+                $profile->status = 'delete';
+                $profile->delete_after = now()->addMonth();
+                $profile->save();
+                AccountService::del($profile->id);
+                DeleteRemoteProfilePipeline::dispatch($profile)->onQueue('high');
+            }
+            return [
+                'status' => 200,
+                'msg' => 'deleted',
+            ];
+        } else if($action === 'refresh_stats') {
             $profile->following_count = DB::table('followers')->whereProfileId($user->profile_id)->count();
             $profile->followers_count = DB::table('followers')->whereFollowingId($user->profile_id)->count();
             $statusCount = Status::whereProfileId($user->profile_id)
@@ -496,6 +591,51 @@ class AdminApiController extends Controller
                 ])
                 ->accessLevel('admin')
                 ->save();
+        } else if($action === 'unlisted') {
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($profile->id)
+                ->objectType('App\Profile::class')
+                ->user($request->user())
+                ->action('admin.user.moderate')
+                ->metadata([
+                    'action' => $action,
+                    'message' => 'Success!'
+                ])
+                ->accessLevel('admin')
+                ->save();
+            $profile->unlisted = !$profile->unlisted;
+            $profile->save();
+        } else if($action === 'cw') {
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($profile->id)
+                ->objectType('App\Profile::class')
+                ->user($request->user())
+                ->action('admin.user.moderate')
+                ->metadata([
+                    'action' => $action,
+                    'message' => 'Success!'
+                ])
+                ->accessLevel('admin')
+                ->save();
+            $profile->cw = !$profile->cw;
+            $profile->save();
+        } else if($action === 'no_autolink') {
+            ModLogService::boot()
+                ->objectUid($profile->id)
+                ->objectId($profile->id)
+                ->objectType('App\Profile::class')
+                ->user($request->user())
+                ->action('admin.user.moderate')
+                ->metadata([
+                    'action' => $action,
+                    'message' => 'Success!'
+                ])
+                ->accessLevel('admin')
+                ->save();
+            $profile->no_autolink = !$profile->no_autolink;
+            $profile->save();
         } else {
             $profile->{$action} = filter_var($request->input('value'), FILTER_VALIDATE_BOOLEAN);
             $profile->save();

+ 20 - 0
app/Services/NetworkTimelineService.php

@@ -72,6 +72,26 @@ class NetworkTimelineService
 		return Redis::zcard(self::CACHE_KEY);
 	}
 
+    public static function deleteByProfileId($profileId)
+    {
+        $res = Redis::zrange(self::CACHE_KEY, 0, '-1');
+        if(!$res) {
+            return;
+        }
+        foreach($res as $postId) {
+            $s = StatusService::get($postId);
+            if(!$s) {
+                self::rem($postId);
+                continue;
+            }
+            if($s['account']['id'] == $profileId) {
+                self::rem($postId);
+            }
+        }
+
+        return;
+    }
+
 	public static function warmCache($force = false, $limit = 100)
 	{
 		if(self::count() == 0 || $force == true) {

+ 20 - 0
app/Services/PublicTimelineService.php

@@ -72,6 +72,26 @@ class PublicTimelineService {
 		return Redis::zcard(self::CACHE_KEY);
 	}
 
+    public static function deleteByProfileId($profileId)
+    {
+        $res = Redis::zrange(self::CACHE_KEY, 0, '-1');
+        if(!$res) {
+            return;
+        }
+        foreach($res as $postId) {
+            $s = StatusService::get($postId);
+            if(!$s) {
+                self::rem($postId);
+                continue;
+            }
+            if($s['account']['id'] == $profileId) {
+                self::rem($postId);
+            }
+        }
+
+        return;
+    }
+
 	public static function warmCache($force = false, $limit = 100)
 	{
 		if(self::count() == 0 || $force == true) {