Update AdminReportController, add story report support

This commit is contained in:
Daniel Supernault 2024-02-26 21:39:09 -07:00
parent 767522a85c
commit a16309ac18
No known key found for this signature in database
GPG key ID: 23740873EE6F76A1

View file

@ -2,38 +2,31 @@
namespace App\Http\Controllers\Admin;
use App\AccountInterstitial;
use App\Http\Resources\AdminReport;
use App\Http\Resources\AdminSpamReport;
use App\Jobs\DeletePipeline\DeleteAccountPipeline;
use App\Jobs\DeletePipeline\DeleteRemoteProfilePipeline;
use App\Jobs\StatusPipeline\RemoteStatusDelete;
use App\Jobs\StatusPipeline\StatusDelete;
use App\Jobs\StoryPipeline\StoryDelete;
use App\Notification;
use App\Profile;
use App\Report;
use App\Services\AccountService;
use App\Services\ModLogService;
use App\Services\NetworkTimelineService;
use App\Services\NotificationService;
use App\Services\PublicTimelineService;
use App\Services\StatusService;
use App\Status;
use App\Story;
use App\User;
use Cache;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use App\Services\AccountService;
use App\Services\StatusService;
use App\{
AccountInterstitial,
Contact,
Hashtag,
Newsroom,
Notification,
OauthClient,
Profile,
Report,
Status,
Story,
User
};
use Illuminate\Validation\Rule;
use App\Services\StoryService;
use App\Services\ModLogService;
use App\Jobs\DeletePipeline\DeleteAccountPipeline;
use App\Jobs\DeletePipeline\DeleteRemoteProfilePipeline;
use App\Jobs\StatusPipeline\StatusDelete;
use App\Jobs\StatusPipeline\RemoteStatusDelete;
use App\Http\Resources\AdminReport;
use App\Http\Resources\AdminSpamReport;
use App\Services\NotificationService;
use App\Services\PublicTimelineService;
use App\Services\NetworkTimelineService;
trait AdminReportController
{
@ -53,7 +46,7 @@ trait AdminReportController
$mailVerifications = Redis::scard('email:manual');
if ($filter == 'open' && $page == 1) {
$reports = Cache::remember('admin-dash:reports:list-cache', 300, function() use($page, $filter) {
$reports = Cache::remember('admin-dash:reports:list-cache', 300, function () use ($filter) {
return Report::whereHas('status')
->whereHas('reportedUser')
->whereHas('reporter')
@ -87,6 +80,7 @@ trait AdminReportController
if ($request->has('ref') && $request->input('ref') == 'email') {
return redirect('/i/admin/reports?tab=report&id='.$report->id);
}
return view('admin.reports.show', compact('report'));
}
@ -96,6 +90,7 @@ trait AdminReportController
->whereNull('appeal_handled_at')
->latest()
->paginate(6);
return view('admin.reports.appeals', compact('appeals'));
}
@ -105,13 +100,14 @@ trait AdminReportController
->whereNull('appeal_handled_at')
->findOrFail($id);
$meta = json_decode($appeal->meta);
return view('admin.reports.show_appeal', compact('appeal', 'meta'));
}
public function spam(Request $request)
{
$this->validate($request, [
'tab' => 'sometimes|in:home,not-spam,spam,settings,custom,exemptions'
'tab' => 'sometimes|in:home,not-spam,spam,settings,custom,exemptions',
]);
$tab = $request->input('tab', 'home');
@ -143,6 +139,7 @@ trait AdminReportController
if (config('database.default') != 'mysql') {
return 0;
}
return AccountInterstitial::selectRaw('*, count(id) as counter')
->whereType('post.autospam')
->groupBy('user_id')
@ -152,11 +149,11 @@ trait AdminReportController
$avgOpen = Cache::remember('admin-dash:reports:spam-count:avgopen', 43200, function () {
if (config('database.default') != 'mysql') {
return "0";
return '0';
}
$seconds = AccountInterstitial::selectRaw('DATE(created_at) AS start_date, AVG(TIME_TO_SEC(TIMEDIFF(appeal_handled_at, created_at))) AS timediff')->whereType('post.autospam')->whereNotNull('appeal_handled_at')->where('created_at', '>', now()->subMonth())->get();
if (! $seconds) {
return "0";
return '0';
}
$mins = floor($seconds->avg('timediff') / 60);
@ -170,7 +167,7 @@ trait AdminReportController
return floor($mins / 60 / 24).' day(s)';
});
$avgCount = $totalCount && $avg ? floor($totalCount / $avg) : "0";
$avgCount = $totalCount && $avg ? floor($totalCount / $avg) : '0';
if (in_array($tab, ['home', 'spam', 'not-spam'])) {
$appeals = AccountInterstitial::whereType('post.autospam')
@ -194,18 +191,20 @@ trait AdminReportController
$appeals = $appeals->appends(['tab' => $tab]);
}
} else {
$appeals = new class {
public function count() {
$appeals = new class
{
public function count()
{
return 0;
}
public function render() {
return;
public function render()
{
}
};
}
return view('admin.reports.spam', compact('tab', 'appeals', 'openCount', 'monthlyCount', 'totalCount', 'avgCount', 'avgOpen', 'uncategorized'));
}
@ -217,6 +216,7 @@ trait AdminReportController
return redirect('/i/admin/reports?tab=autospam&id='.$appeal->id);
}
$meta = json_decode($appeal->meta);
return view('admin.reports.show_spam', compact('appeal', 'meta'));
}
@ -255,13 +255,14 @@ trait AdminReportController
});
Cache::forget('admin-dash:reports:spam-sync');
return redirect('/i/admin/reports/autospam');
}
public function updateSpam(Request $request, $id)
{
$this->validate($request, [
'action' => 'required|in:dismiss,approve,dismiss-all,approve-all,delete-account,mark-spammer'
'action' => 'required|in:dismiss,approve,dismiss-all,approve-all,delete-account,mark-spammer',
]);
$action = $request->input('action');
@ -307,6 +308,7 @@ trait AdminReportController
Cache::forget('profiles:private');
DeleteAccountPipeline::dispatch($user);
return;
}
@ -318,6 +320,7 @@ trait AdminReportController
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('admin-dash:reports:spam-count');
return $res;
}
@ -330,6 +333,7 @@ trait AdminReportController
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('admin-dash:reports:spam-count');
return $res;
}
@ -355,6 +359,7 @@ trait AdminReportController
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('admin-dash:reports:spam-count');
return $res;
}
@ -370,7 +375,7 @@ trait AdminReportController
$pro->update([
'unlisted' => true,
'cw' => true,
'no_autolink' => true
'no_autolink' => true,
]);
Status::whereProfileId($pro->id)
@ -386,6 +391,7 @@ trait AdminReportController
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('admin-dash:reports:spam-count');
return $res;
}
@ -411,7 +417,7 @@ trait AdminReportController
public function updateAppeal(Request $request, $id)
{
$this->validate($request, [
'action' => 'required|in:dismiss,approve'
'action' => 'required|in:dismiss,approve',
]);
$action = $request->input('action');
@ -423,6 +429,7 @@ trait AdminReportController
$appeal->appeal_handled_at = now();
$appeal->save();
Cache::forget('admin-dash:reports:ai-count');
return redirect('/i/admin/reports/appeals');
}
@ -441,7 +448,7 @@ trait AdminReportController
break;
default:
# code...
// code...
break;
}
@ -541,7 +548,7 @@ trait AdminReportController
'3' => 'unlist',
'4' => 'delete',
'5' => 'shadowban',
'6' => 'ban'
'6' => 'ban',
];
}
@ -549,7 +556,7 @@ trait AdminReportController
{
$this->validate($request, [
'action' => 'required|integer|min:1|max:10',
'ids' => 'required|array'
'ids' => 'required|array',
]);
$action = $this->actionMap()[$request->input('action')];
$ids = $request->input('ids');
@ -559,8 +566,9 @@ trait AdminReportController
}
$res = [
'message' => 'Success',
'code' => 200
'code' => 200,
];
return response()->json($res);
}
@ -584,6 +592,7 @@ trait AdminReportController
return [];
}
$account['email'] = $user->email;
return $account;
})
->filter(function ($res) {
@ -591,6 +600,7 @@ trait AdminReportController
})
->values();
}
return view('admin.reports.mail_verification', compact('reports', 'ignored'));
}
@ -598,6 +608,7 @@ trait AdminReportController
{
$id = $request->input('id');
Redis::sadd('email:manual-ignored', $id);
return redirect('/i/admin/reports');
}
@ -609,12 +620,14 @@ trait AdminReportController
Redis::srem('email:manual-ignored', $id);
$user->email_verified_at = now();
$user->save();
return redirect('/i/admin/reports');
}
public function reportMailVerifyClearIgnored(Request $request)
{
Redis::del('email:manual-ignored');
return [200];
}
@ -627,8 +640,9 @@ trait AdminReportController
'autospam' => AccountInterstitial::whereType('post.autospam')->count(),
'autospam_open' => AccountInterstitial::whereType('post.autospam')->whereNull(['appeal_handled_at'])->count(),
'appeals' => AccountInterstitial::whereNotNull('appeal_requested_at')->whereNull('appeal_handled_at')->count(),
'email_verification_requests' => Redis::scard('email:manual')
'email_verification_requests' => Redis::scard('email:manual'),
];
return $stats;
}
@ -654,6 +668,7 @@ trait AdminReportController
public function reportsApiGet(Request $request, $id)
{
$report = Report::findOrFail($id);
return new AdminReport($report);
}
@ -663,8 +678,8 @@ trait AdminReportController
'object_id' => 'required',
'object_type' => 'required',
'id' => 'required',
'action' => 'required|in:ignore,nsfw,unlist,private,delete',
'action_type' => 'required|in:post,profile'
'action' => 'required|in:ignore,nsfw,unlist,private,delete,delete-all',
'action_type' => 'required|in:post,profile,story',
]);
$report = Report::whereObjectId($request->input('object_id'))->findOrFail($request->input('id'));
@ -673,11 +688,92 @@ trait AdminReportController
return $this->reportsHandleProfileAction($report, $request->input('action'));
} elseif ($request->input('action_type') === 'post') {
return $this->reportsHandleStatusAction($report, $request->input('action'));
} elseif ($request->input('action_type') === 'story') {
return $this->reportsHandleStoryAction($report, $request->input('action'));
}
return $report;
}
protected function reportsHandleStoryAction($report, $action)
{
switch ($action) {
case 'ignore':
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now(),
]);
return [200];
break;
case 'delete':
$profile = Profile::find($report->reported_profile_id);
$story = Story::whereProfileId($profile->id)->find($report->object_id);
abort_if(! $story, 400, 'Invalid or missing story');
$story->active = false;
$story->save();
ModLogService::boot()
->objectUid($profile->id)
->objectId($report->object_id)
->objectType('App\Story::class')
->user(request()->user())
->action('admin.user.moderate')
->metadata([
'action' => 'delete',
'message' => 'Success!',
])
->accessLevel('admin')
->save();
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now(),
]);
StoryDelete::dispatch($story)->onQueue('story');
return [200];
break;
case 'delete-all':
$profile = Profile::find($report->reported_profile_id);
$stories = Story::whereProfileId($profile->id)->whereActive(true)->get();
abort_if(! $stories || ! $stories->count(), 400, 'Invalid or missing stories');
ModLogService::boot()
->objectUid($profile->id)
->objectId($report->object_id)
->objectType('App\Story::class')
->user(request()->user())
->action('admin.user.moderate')
->metadata([
'action' => 'delete-all',
'message' => 'Success!',
])
->accessLevel('admin')
->save();
Report::where('reported_profile_id', $profile->id)
->whereObjectType('App\Story')
->whereNull('admin_seen')
->update([
'admin_seen' => now(),
]);
$stories->each(function ($story) {
StoryDelete::dispatch($story)->onQueue('story');
});
return [200];
break;
}
}
protected function reportsHandleProfileAction($report, $action)
{
switch ($action) {
@ -685,8 +781,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -725,7 +822,7 @@ trait AdminReportController
->action('admin.user.moderate')
->metadata([
'action' => 'cw',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -734,8 +831,9 @@ trait AdminReportController
->whereObjectType($report->object_type)
->update([
'nsfw' => true,
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -775,7 +873,7 @@ trait AdminReportController
->action('admin.user.moderate')
->metadata([
'action' => 'unlisted',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -783,8 +881,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -824,7 +923,7 @@ trait AdminReportController
->action('admin.user.moderate')
->metadata([
'action' => 'private',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -832,8 +931,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -884,7 +984,7 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
if ($profile->user_id) {
@ -906,6 +1006,7 @@ trait AdminReportController
AccountService::del($profile->id);
DeleteRemoteProfilePipeline::dispatch($profile)->onQueue('high');
}
return [200];
break;
}
@ -918,8 +1019,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -943,7 +1045,7 @@ trait AdminReportController
->action('admin.status.moderate')
->metadata([
'action' => 'cw',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -952,8 +1054,9 @@ trait AdminReportController
->whereObjectType($report->object_type)
->update([
'nsfw' => true,
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -980,7 +1083,7 @@ trait AdminReportController
->action('admin.status.moderate')
->metadata([
'action' => 'private',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -988,8 +1091,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -1018,7 +1122,7 @@ trait AdminReportController
->action('admin.status.moderate')
->metadata([
'action' => 'unlist',
'message' => 'Success!'
'message' => 'Success!',
])
->accessLevel('admin')
->save();
@ -1026,8 +1130,9 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
break;
@ -1055,7 +1160,7 @@ trait AdminReportController
Report::whereObjectId($report->object_id)
->whereObjectType($report->object_type)
->update([
'admin_seen' => now()
'admin_seen' => now(),
]);
return [200];
@ -1103,6 +1208,7 @@ trait AdminReportController
Cache::forget('admin-dash:reports:spam-count');
Cache::forget('pf:bouncer_v0:exemption_by_pid:'.$report->user->profile_id);
Cache::forget('pf:bouncer_v0:recent_by_pid:'.$report->user->profile_id);
return [$action, $report];
}
@ -1150,7 +1256,7 @@ trait AdminReportController
->whereUserId($appeal->user_id)
->update([
'appeal_handled_at' => now(),
'is_spam' => true
'is_spam' => true,
]);
}
@ -1218,6 +1324,7 @@ trait AdminReportController
public function reportsApiSpamGet(Request $request, $id)
{
$report = AccountInterstitial::findOrFail($id);
return new AdminSpamReport($report);
}
}