diff --git a/app/Http/Controllers/Appeal/AppealActionController.php b/app/Http/Controllers/Appeal/AppealActionController.php new file mode 100644 index 00000000..1df15df0 --- /dev/null +++ b/app/Http/Controllers/Appeal/AppealActionController.php @@ -0,0 +1,248 @@ +middleware('auth'); + } + + /** + * Process a appeal status change request + * @param Request $request Request object to process + * @param Appeal $appeal Appeal object to process + * @param string $logEntry Log action name, for example 'reserve' or 'sent for CheckUser review' + * @param Closure $doAction Closure to take action on the appeal object + * @param Closure|null $validate Check if this action can be taken. Return a string to fail, or true to pass. + * @param int $logProtection Log protection level. Use a const from LogEntry::LOG_PROTECTION_* + * @param string $requiredPermission Permission to take this object + * @return object Response object + */ + private function doAction( + Request $request, + Appeal $appeal, + string $logEntry, + Closure $doAction, + ?Closure $validate = null, + int $logProtection = LogEntry::LOG_PROTECTION_NONE, + string $requiredPermission = 'update' + ) + { + // first off, make sure that we can do the action + $this->authorize($requiredPermission, $appeal); + + if ($validate) { + $validationResult = $validate($appeal, $request); + if ($validationResult && $validationResult !== true) { + abort(403, $validationResult); + return response($validationResult); // unreachable, in theory + } + } + + DB::transaction(function () use ($appeal, $request, $doAction, $logEntry, $logProtection) { + $ip = $request->ip(); + $ua = $request->userAgent(); + $lang = $request->header('Accept-Language'); + + $reason = $doAction($appeal, $request); + if (!$reason || empty($reason)) { + $reason = null; + } + + LogEntry::create([ + 'user_id' => $request->user()->id, + 'model_id' => $appeal->id, + 'model_type' => Appeal::class, + 'reason' => $reason, + 'action' => $logEntry, + 'ip' => $ip, + 'ua' => $ua . " " . $lang, + 'protected' => $logProtection, + ]); + }); + + return redirect()->route('appeal.view', [ $appeal ]); + } + + public function reserve(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 'reserve', + function (Appeal $appeal, Request $request) { + $appeal->handlingadmin = $request->user()->id; + $appeal->save(); + }, + function (Appeal $appeal) { + return $appeal->handlingadmin + ? 'This appeal has already been reserved.' + : true; + } + ); + } + + public function close(Request $request, Appeal $appeal, string $status) + { + if (!in_array($status, [ Appeal::STATUS_ACCEPT, Appeal::STATUS_DECLINE, Appeal::STATUS_EXPIRE ])) { + return abort(400, 'Invalid status.'); + } + + $this->doAction( + $request, + $appeal, + 'closed - ' . strtolower($status), + function (Appeal $appeal) use ($status) { + $appeal->status = $status; + $appeal->save(); + }, + ); + + return redirect()->route('appeal.list'); + } + + public function release(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 'release', + function (Appeal $appeal) { + $appeal->handlingadmin = null; + $appeal->save(); + }, + function (Appeal $appeal, Request $request) { + if ($appeal->handlingadmin) { + /** @var User $user */ + $user = $request->user(); + if ($appeal->handlingadmin === $user->id) { + return true; + } + + return $user->hasAnySpecifiedLocalOrGlobalPerms($appeal->wiki, [ 'tooladmin' ]) + ? true + : "Only tool administrators can force release appeals."; + } + + return 'No-one has reserved this appeal.'; + } + ); + } + + public function sendToTooladminReview(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 'sent for tool administrator review', + function (Appeal $appeal) { + $appeal->status = Appeal::STATUS_ADMIN; + $appeal->save(); + }, + function (Appeal $appeal) { + return $appeal->status === Appeal::STATUS_ADMIN + ? 'This appeal is already waiting for tool administrator review.' + : true; + } + ); + } + + public function sendToCheckUserReview(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 'sent for CheckUser review', + function (Appeal $appeal, Request $request) { + $reason = $request->validate([ + 'cu_reason' => 'required|string|min:3|max:190', + ])['cu_reason']; + + $appeal->status = Appeal::STATUS_CHECKUSER; + $appeal->save(); + + return $reason; + }, + function (Appeal $appeal) { + return $appeal->status === Appeal::STATUS_CHECKUSER + ? 'This appeal is already waiting for CheckUser review.' + : true; + } + ); + } + + public function reOpen(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 're-open', + function (Appeal $appeal) { + $appeal->status = Appeal::STATUS_OPEN; + $appeal->save(); + }, + function (Appeal $appeal, Request $request) { + /** @var User $user */ + $user = $request->user(); + + if (in_array($appeal->status, + [ Appeal::STATUS_ACCEPT, Appeal::STATUS_EXPIRE, Appeal::STATUS_DECLINE, + Appeal::STATUS_CHECKUSER, Appeal::STATUS_ADMIN, ]) + && $user->hasAnySpecifiedLocalOrGlobalPerms($appeal->wiki, + [ 'tooladmin', 'checkuser', 'oversight', 'steward', 'staff', ])) { + return true; + } + + return $user->hasAnySpecifiedPermsOnAnyWiki([ 'developer' ]) + ? true + : 'This appeal is currently not in a status where you can re-open it.'; + } + ); + } + + public function invalidate(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 'closed as invalid', + function (Appeal $appeal) { + $appeal->status = Appeal::STATUS_INVALID; + $appeal->save(); + }, + null, + LogEntry::LOG_PROTECTION_ADMIN, + 'performDeveloperActions', + ); + } + + public function reverifyBlockDetails(Request $request, Appeal $appeal) + { + return $this->doAction( + $request, + $appeal, + 're-verify block details', + function (Appeal $appeal) { + GetBlockDetailsJob::dispatch($appeal); + }, + function (Appeal $appeal) { + return in_array($appeal->status, [ Appeal::STATUS_VERIFY, Appeal::STATUS_NOTFOUND ]) + ? true + : 'Block details for this appeal have already been found.'; + }, + LogEntry::LOG_PROTECTION_NONE, + 'performDeveloperActions', + ); + } +} diff --git a/app/Http/Controllers/AppealController.php b/app/Http/Controllers/AppealController.php index e114426c..ca1741d3 100644 --- a/app/Http/Controllers/AppealController.php +++ b/app/Http/Controllers/AppealController.php @@ -191,7 +191,7 @@ public function search(Request $request) $number = intval(substr($search, 1), 10); } - $wikis = collect(MwApiUrls::getSupportedWikis(true)); + $wikis = collect(MediaWikiRepository::getSupportedTargets(true)); // For users who aren't developers, stewards or staff, show appeals only for own wikis if (!$user->hasAnySpecifiedLocalOrGlobalPerms(['*'], ['steward', 'staff', 'developer'])) { @@ -288,7 +288,7 @@ public function checkuser(Appeal $appeal, Request $request) LogEntry::create(['user_id' => $user, 'model_id' => $appeal->id, 'model_type' => Appeal::class, 'action' => 'checkuser', 'reason' => $reason, 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_FUNCTIONARY]); return redirect('appeal/' . $appeal->id); } - + public function comment($id, Request $request) { if (!Auth::check()) { @@ -429,105 +429,6 @@ public function respondCustom(Appeal $appeal) return view('appeals.custom', ['appeal' => $appeal, 'userlist' => $userlist]); } - public function reserve(Appeal $appeal, Request $request) - { - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - $user = Auth::id(); - - $admin = Permission::checkAdmin($user, $appeal->wiki); - abort_unless($admin,403, 'You are not an administrator.'); - abort_if($appeal->handlingadmin, 403, 'This appeal has already been reserved.'); - $appeal->handlingadmin = Auth::id(); - $appeal->save(); - LogEntry::create(['user_id' => $user, 'model_id' => $appeal->id, 'model_type' => Appeal::class, 'action' => 'reserve', 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_NONE]); - - return redirect('appeal/' . $appeal->id); - } - - public function release($id, Request $request) - { - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - $user = Auth::id(); - $appeal = Appeal::findOrFail($id); - $admin = Permission::checkAdmin($user, $appeal->wiki); - if ($admin) { - if (isset($appeal->handlingadmin)) { - $appeal->handlingadmin = null; - $appeal->save(); - $log = LogEntry::create(array('user_id' => $user, 'model_id' => $id, 'model_type' => Appeal::class, 'action' => 'release', 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_NONE)); - } else { - abort(403); - } - return redirect('appeal/' . $id); - } else { - abort(403); - } - } - - public function open($id, Request $request) - { - $appeal = Appeal::findOrFail($id); - $user = Auth::id(); - - $admin = Permission::checkAdmin($user, $appeal->wiki); - abort_if(!$admin,403,"You are not an administrator on the wiki this appeal is for"); - - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - $user = Auth::id(); - - if ($appeal->status == Appeal::STATUS_ACCEPT || $appeal->status == Appeal::STATUS_EXPIRE || $appeal->status == Appeal::STATUS_DECLINE || $appeal->status == Appeal::STATUS_CHECKUSER || $appeal->status == Appeal::STATUS_ADMIN) { - $appeal->status = Appeal::STATUS_OPEN; - $appeal->save(); - LogEntry::create(array('user_id' => $user, 'model_id' => $id, 'model_type' => Appeal::class, 'action' => 're-open', 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_NONE)); - return redirect('appeal/' . $id); - } else { - abort(403); - } -} - - public function invalidate($id, Request $request) - { - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - $user = Auth::id(); - $appeal = Appeal::findOrFail($id); - $dev = Permission::checkSecurity($user, "DEVELOPER", "*"); - if ($dev && $appeal->status !== Appeal::STATUS_INVALID) { - $appeal->status = Appeal::STATUS_INVALID; - $appeal->save(); - $log = LogEntry::create(array('user_id' => $user, 'model_id' => $id, 'model_type' => Appeal::class, 'action' => 'closed - invalidate', 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_ADMIN)); - return redirect('appeal/' . $id); - } else { - abort(403); - } - } - - public function close($id, $type, Request $request) - { - $appeal = Appeal::findOrFail($id); - $user = Auth::id(); - $admin = Permission::checkAdmin($user, $appeal->wiki); - abort_if(!$admin,403,"You are not an administrator on the wiki this appeal is for"); - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - if ($admin) { - $appeal->status = strtoupper($type); - $appeal->save(); - $log = LogEntry::create(array('user_id' => $user, 'model_id' => $id, 'model_type' => Appeal::class, 'action' => 'closed - ' . $type, 'ip' => $ip, 'ua' => $ua . " " . $lang, 'protected' => LogEntry::LOG_PROTECTION_NONE)); - return redirect('/review'); - } else { - abort(403); - } - } - public function checkuserreview(Request $request, Appeal $appeal) { $ua = $request->header('User-Agent'); @@ -559,56 +460,4 @@ public function checkuserreview(Request $request, Appeal $appeal) return redirect()->back(); } - - public function admin(Request $request, Appeal $appeal) - { - $user = Auth::id(); - $admin = Permission::checkAdmin($user, $appeal->wiki); - abort_unless($admin,403,"You are not an administrator on the wiki this appeal is for"); - abort_if($appeal->status === Appeal::STATUS_ADMIN, 400, 'This appeal is already waiting for tool administrator review.'); - - $ua = $request->userAgent(); - $ip = $request->ip(); - $lang = $request->header('Accept-Language'); - - $appeal->status = Appeal::STATUS_ADMIN; - $appeal->save(); - LogEntry::create([ - 'user_id' => $user, - 'model_id' => $appeal->id, - 'model_type' => Appeal::class, - 'action' => 'sent for admin review', - 'ip' => $ip, - 'ua' => $ua . " " . $lang, - 'protected' => LogEntry::LOG_PROTECTION_NONE - ]); - - return redirect()->back(); - } - - public function findagain(Request $request, Appeal $appeal) - { - /** @var User $user */ - $user = $request->user(); - - $ua = $request->server('HTTP_USER_AGENT'); - $ip = $request->ip(); - $lang = $request->server('HTTP_ACCEPT_LANGUAGE'); - - $dev = $user->hasAnySpecifiedLocalOrGlobalPerms('*', 'developer'); - abort_unless($dev,403,"You are not an UTRS developer"); - abort_if($appeal->status !== Appeal::STATUS_NOTFOUND && $appeal->status !== Appeal::STATUS_VERIFY, 400, 'Appeal details were already found.'); - - GetBlockDetailsJob::dispatch($appeal); - LogEntry::create([ - 'user_id' => Auth::id(), - 'model_id'=> $appeal->id, - 'model_type'=> Appeal::class, - 'action'=>'reverify block', - 'ip' => $ip, - 'ua' => $ua . " " .$lang - ]); - - return redirect()->back(); - } } diff --git a/app/Policies/AppealPolicy.php b/app/Policies/AppealPolicy.php index f40b7286..85965317 100644 --- a/app/Policies/AppealPolicy.php +++ b/app/Policies/AppealPolicy.php @@ -33,7 +33,7 @@ public function viewAny(User $user) public function view(User $user, Appeal $appeal) { if (!$user->hasAnySpecifiedLocalOrGlobalPerms($appeal->wiki, ['admin'])) { - return false; + return $this->deny('Only ' . $appeal->wiki . ' administrators are able to see this appeal.'); } if ($appeal->status === Appeal::STATUS_INVALID) { @@ -74,4 +74,17 @@ public function update(User $user, Appeal $appeal) return $user->hasAnySpecifiedLocalOrGlobalPerms($appeal->wiki, ['admin']) ? true : $this->deny('Only administrators can take actions on appeals.'); } + + /** + * Determine whether the user can take developer actions on this appeal. + * + * @param User $user + * @param Appeal $appeal + * @return mixed + */ + public function performDeveloperActions(User $user, Appeal $appeal) + { + // Handle via Gate::before() + return $this->deny('Only developers can take developer actions on appeals.'); + } } diff --git a/resources/views/appeals/appeal.blade.php b/resources/views/appeals/appeal.blade.php index d2e27cdb..3e8268b8 100644 --- a/resources/views/appeals/appeal.blade.php +++ b/resources/views/appeals/appeal.blade.php @@ -158,10 +158,12 @@ class="btn btn-warning"> @if($info->status === Appeal::STATUS_ACCEPT || $info->status === Appeal::STATUS_DECLINE || $info->status === Appeal::STATUS_EXPIRE) @if($perms['functionary'])
- - Re-open - - Oversight appeal +
+ @csrf + +
@else