diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index 90c195a28..ad34f92ae 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -28,6 +28,7 @@ use App\Transformer\Api\{ }; use App\Util\Media\Filter; use App\Jobs\StatusPipeline\NewStatusPipeline; +use App\Jobs\ModPipeline\HandleSpammerPipeline; use League\Fractal\Serializer\ArraySerializer; use League\Fractal\Pagination\IlluminatePaginatorAdapter; use Illuminate\Validation\Rule; @@ -175,7 +176,8 @@ class InternalApiController extends Controller Rule::in([ 'addcw', 'remcw', - 'unlist' + 'unlist', + 'spammer' ]) ], 'item_id' => 'required|integer|min:1', @@ -310,6 +312,23 @@ class InternalApiController extends Controller $u->save(); } break; + + case 'spammer': + $status = Status::findOrFail($item_id); + HandleSpammerPipeline::dispatch($status->profile); + ModLogService::boot() + ->user(Auth::user()) + ->objectUid($status->profile->user_id) + ->objectId($status->id) + ->objectType('App\User::class') + ->action('admin.status.moderate') + ->metadata([ + 'action' => 'spammer', + 'message' => 'Success!' + ]) + ->accessLevel('admin') + ->save(); + break; } Cache::forget('_api:statuses:recent_9:' . $status->profile_id); diff --git a/app/Jobs/ModPipeline/HandleSpammerPipeline.php b/app/Jobs/ModPipeline/HandleSpammerPipeline.php new file mode 100644 index 000000000..0e5b4042d --- /dev/null +++ b/app/Jobs/ModPipeline/HandleSpammerPipeline.php @@ -0,0 +1,52 @@ +profile = $profile; + } + + public function handle() + { + $profile = $this->profile; + + $profile->unlisted = true; + $profile->cw = true; + $profile->no_autolink = true; + $profile->save(); + + Status::whereProfileId($profile->id) + ->chunk(50, function($statuses) { + foreach($statuses as $status) { + $status->is_nsfw = true; + $status->scope = $status->scope === 'public' ? 'unlisted' : $status->scope; + $status->visibility = $status->scope; + $status->save(); + StatusService::del($status->id); + } + }); + + Cache::forget('_api:statuses:recent_9:'.$profile->id); + + return 1; + } +} diff --git a/resources/assets/js/components/partials/ContextMenu.vue b/resources/assets/js/components/partials/ContextMenu.vue index 5a398ba74..35402d819 100644 --- a/resources/assets/js/components/partials/ContextMenu.vue +++ b/resources/assets/js/components/partials/ContextMenu.vue @@ -37,6 +37,10 @@
Unlist from Timelines
Remove Content Warning
Add Content Warning
+
+ Mark as Spammer
+ Unlist + CW existing and future posts +
Cancel
@@ -465,99 +469,129 @@ moderatePost(status, action, $event) { let username = status.account.username; + let pid = status.id; let msg = ''; let self = this; switch(action) { case 'addcw': - msg = 'Are you sure you want to add a content warning to this post?'; - swal({ - title: 'Confirm', - text: msg, - icon: 'warning', - buttons: true, - dangerMode: true - }).then(res => { - if(res) { - axios.post('/api/v2/moderator/action', { - action: action, - item_id: status.id, - item_type: 'status' - }).then(res => { - swal('Success', 'Successfully added content warning', 'success'); - status.sensitive = true; - self.ctxModMenuClose(); - }).catch(err => { - swal( - 'Error', - 'Something went wrong, please try again later.', - 'error' - ); - self.ctxModMenuClose(); - }); - } - }); + msg = 'Are you sure you want to add a content warning to this post?'; + swal({ + title: 'Confirm', + text: msg, + icon: 'warning', + buttons: true, + dangerMode: true + }).then(res => { + if(res) { + axios.post('/api/v2/moderator/action', { + action: action, + item_id: status.id, + item_type: 'status' + }).then(res => { + swal('Success', 'Successfully added content warning', 'success'); + status.sensitive = true; + self.ctxModMenuClose(); + }).catch(err => { + swal( + 'Error', + 'Something went wrong, please try again later.', + 'error' + ); + self.ctxModMenuClose(); + }); + } + }); break; case 'remcw': - msg = 'Are you sure you want to remove the content warning on this post?'; - swal({ - title: 'Confirm', - text: msg, - icon: 'warning', - buttons: true, - dangerMode: true - }).then(res => { - if(res) { - axios.post('/api/v2/moderator/action', { - action: action, - item_id: status.id, - item_type: 'status' - }).then(res => { - swal('Success', 'Successfully added content warning', 'success'); - status.sensitive = false; - self.ctxModMenuClose(); - }).catch(err => { - swal( - 'Error', - 'Something went wrong, please try again later.', - 'error' - ); - self.ctxModMenuClose(); - }); - } - }); + msg = 'Are you sure you want to remove the content warning on this post?'; + swal({ + title: 'Confirm', + text: msg, + icon: 'warning', + buttons: true, + dangerMode: true + }).then(res => { + if(res) { + axios.post('/api/v2/moderator/action', { + action: action, + item_id: status.id, + item_type: 'status' + }).then(res => { + swal('Success', 'Successfully added content warning', 'success'); + status.sensitive = false; + self.ctxModMenuClose(); + }).catch(err => { + swal( + 'Error', + 'Something went wrong, please try again later.', + 'error' + ); + self.ctxModMenuClose(); + }); + } + }); break; case 'unlist': - msg = 'Are you sure you want to unlist this post?'; - swal({ - title: 'Confirm', - text: msg, - icon: 'warning', - buttons: true, - dangerMode: true - }).then(res => { - if(res) { - axios.post('/api/v2/moderator/action', { - action: action, - item_id: status.id, - item_type: 'status' - }).then(res => { - this.feed = this.feed.filter(f => { - return f.id != status.id; + msg = 'Are you sure you want to unlist this post?'; + swal({ + title: 'Confirm', + text: msg, + icon: 'warning', + buttons: true, + dangerMode: true + }).then(res => { + if(res) { + axios.post('/api/v2/moderator/action', { + action: action, + item_id: status.id, + item_type: 'status' + }).then(res => { + this.feed = this.feed.filter(f => { + return f.id != status.id; + }); + swal('Success', 'Successfully unlisted post', 'success'); + self.ctxModMenuClose(); + }).catch(err => { + self.ctxModMenuClose(); + swal( + 'Error', + 'Something went wrong, please try again later.', + 'error' + ); }); - swal('Success', 'Successfully unlisted post', 'success'); - self.ctxModMenuClose(); - }).catch(err => { - self.ctxModMenuClose(); - swal( - 'Error', - 'Something went wrong, please try again later.', - 'error' - ); - }); - } - }); + } + }); + break; + + case 'spammer': + msg = 'Are you sure you want to mark this user as a spammer? All existing and future posts will be unlisted on timelines and a content warning will be applied.'; + swal({ + title: 'Confirm', + text: msg, + icon: 'warning', + buttons: true, + dangerMode: true + }).then(res => { + if(res) { + axios.post('/api/v2/moderator/action', { + action: action, + item_id: status.id, + item_type: 'status' + }).then(res => { + swal('Success', 'Successfully marked account as spammer', 'success'); + self.ctxModMenuClose(); + }).catch(err => { + self.ctxModMenuClose(); + swal( + 'Error', + 'Something went wrong, please try again later.', + 'error' + ); + }); + } + }); break; } },