Skip to content

Commit

Permalink
Appeal action refactor (#292)
Browse files Browse the repository at this point in the history
Split appeal actions to a new controller (except replying, those are too different and will be handled separately) and add tests for them.
  • Loading branch information
supertassu authored Nov 18, 2020
1 parent b7d49ae commit 7917458
Show file tree
Hide file tree
Showing 13 changed files with 764 additions and 192 deletions.
248 changes: 248 additions & 0 deletions app/Http/Controllers/Appeal/AppealActionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
<?php

namespace App\Http\Controllers\Appeal;

use App\Http\Controllers\Controller;
use App\Jobs\GetBlockDetailsJob;
use App\Models\Appeal;
use App\Models\LogEntry;
use App\Models\User;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AppealActionController extends Controller
{
public function __construct()
{
$this->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',
);
}
}
Loading

0 comments on commit 7917458

Please sign in to comment.