WIP: Implement domain blocks

This commit is contained in:
Emelia Smith 2024-03-29 22:48:22 +01:00
parent c96167f2f7
commit 652654e24f
No known key found for this signature in database
5 changed files with 166 additions and 0 deletions

View file

@ -0,0 +1,38 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ApiController extends Controller {
public function json($res, $headers = [], $code = 200) {
return response()->json($res, $code, $this->filterHeaders($headers), JSON_UNESCAPED_SLASHES);
}
public function linksForCollection($paginator) {
$link = null;
if ($paginator->onFirstPage()) {
if ($paginator->hasMorePages()) {
$link = '<'.$paginator->nextPageUrl().'>; rel="prev"';
}
} else {
if ($paginator->previousPageUrl()) {
$link = '<'.$paginator->previousPageUrl().'>; rel="next"';
}
if ($paginator->hasMorePages()) {
$link .= ($link ? ', ' : '').'<'.$paginator->nextPageUrl().'>; rel="prev"';
}
}
return $link;
}
private function filterHeaders($headers) {
return array_filter($headers, function($v, $k) {
return $v != null;
}, ARRAY_FILTER_USE_BOTH);
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace App\Http\Controllers\Api\V1\Admin;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Api\ApiController;
use App\Instance;
use App\Services\InstanceService;
use App\Http\Resources\MastoApi\Admin\DomainBlockResource;
class DomainBlocksController extends ApiController {
public function index(Request $request) {
$this->validate($request, [
'limit' => 'sometimes|integer|max:100|min:1',
]);
$limit = $request->input('limit', 100);
$res = Instance::moderated()
->orderBy('id')
->cursorPaginate($limit)
->withQueryString();
return $this->json(DomainBlockResource::collection($res), [
'Link' => $this->linksForCollection($res)
]);
}
public function show(Request $request, $id) {
$res = Instance::moderated()
->findOrFail($id);
return $this->json(new DomainBlockResource($res));
}
public function create(Request $request) {
$this->validate($request, [
'domain' => 'required|string|min:1|max:120',
'severity' => [
'sometimes',
Rule::in(['noop', 'silence', 'suspend'])
],
'reject_media' => 'sometimes|required|boolean',
'reject_reports' => 'sometimes|required|boolean',
'private_comment' => 'sometimes|string|min:1|max:1000',
'public_comment' => 'sometimes|string|min:1|max:1000',
'obfuscate' => 'sometimes|required|boolean'
]);
$domain = $request->input('domain');
$severity = $request->input('severity');
$private_comment = $request->input('private_comment');
abort_if(!strpos($domain, '.'), 400, 'Invalid domain');
abort_if(!filter_var($domain, FILTER_VALIDATE_DOMAIN), 400, 'Invalid domain');
$existing = Instance::moderated()->whereDomain($domain)->first();
if ($existing) {
return $this->json([
'error' => 'A domain block already exists for this domain',
'existing_domain_block' => new DomainBlockResource($existing)
], [], 422);
}
$domain_block = Instance::updateOrCreate(
[ 'domain' => $domain ],
[ 'banned' => $severity === 'suspend', 'unlisted' => $severity === 'silence', 'notes' => [$private_comment]]
);
InstanceService::refresh();
return $this->json(new DomainBlockResource($domain_block));
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Resources\MastoApi\Admin;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class DomainBlockResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
$severity = 'noop';
if ($this->banned) {
$severity = 'suspend';
} else if ($this->unlisted) {
$severity = 'silence';
}
return [
'id' => $this->id,
'domain' => $this->domain,
'severity' => $severity,
// Using the updated_at value as this is going to be the closest to
// when the domain was banned
'created_at' => $this->updated_at,
// We don't have data for these fields
'reject_media' => false,
'reject_reports' => false,
'private_comment' => $this->notes ? join('; ', $this->notes) : null,
'public_comment' => $this->limit_reason,
'obfuscate' => false
];
}
}

View file

@ -22,6 +22,13 @@ class Instance extends Model
'notes' 'notes'
]; ];
// To get all moderated instances, we need to search where (banned OR unlisted)
public function scopeModerated($query): void {
$query->where(function ($query) {
$query->where('banned', true)->orWhere('unlisted', true);
});
}
public function profiles() public function profiles()
{ {
return $this->hasMany(Profile::class, 'domain', 'domain'); return $this->hasMany(Profile::class, 'domain', 'domain');

View file

@ -101,6 +101,12 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::get('statuses/{id}/history', 'StatusEditController@history')->middleware($middleware); Route::get('statuses/{id}/history', 'StatusEditController@history')->middleware($middleware);
Route::put('statuses/{id}', 'StatusEditController@store')->middleware($middleware); Route::put('statuses/{id}', 'StatusEditController@store')->middleware($middleware);
Route::group(['prefix' => 'admin'], function() use($middleware) {
Route::get('domain_blocks', 'Api\V1\Admin\DomainBlocksController@index')->middleware($middleware);
Route::post('domain_blocks', 'Api\V1\Admin\DomainBlocksController@create')->middleware($middleware);
Route::get('domain_blocks/{id}', 'Api\V1\Admin\DomainBlocksController@show')->middleware($middleware);
})->middleware($middleware);
}); });
Route::group(['prefix' => 'v2'], function() use($middleware) { Route::group(['prefix' => 'v2'], function() use($middleware) {