Merge pull request #4206 from pixelfed/staging

Update v1.1 api, add post moderation endpoint
This commit is contained in:
daniel 2023-02-23 21:53:52 -07:00 committed by GitHub
commit e1f7ae655f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 933 additions and 779 deletions

View file

@ -6,6 +6,7 @@ use Illuminate\Http\Request;
use App\Models\AdminInvite; use App\Models\AdminInvite;
use App\Profile; use App\Profile;
use App\User; use App\User;
use Purify;
use App\Util\Lexer\RestrictedNames; use App\Util\Lexer\RestrictedNames;
use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -148,9 +149,57 @@ class AdminInviteController extends Controller
{ {
$this->validate($request, [ $this->validate($request, [
'token' => 'required', 'token' => 'required',
'username' => 'required', 'username' => [
'name' => 'nullable', 'required',
'email' => 'required|email', 'min:2',
'max:15',
'unique:users',
function ($attribute, $value, $fail) {
$dash = substr_count($value, '-');
$underscore = substr_count($value, '_');
$period = substr_count($value, '.');
if(ends_with($value, ['.php', '.js', '.css'])) {
return $fail('Username is invalid.');
}
if(($dash + $underscore + $period) > 1) {
return $fail('Username is invalid. Can only contain one dash (-), period (.) or underscore (_).');
}
if (!ctype_alnum($value[0])) {
return $fail('Username is invalid. Must start with a letter or number.');
}
if (!ctype_alnum($value[strlen($value) - 1])) {
return $fail('Username is invalid. Must end with a letter or number.');
}
$val = str_replace(['_', '.', '-'], '', $value);
if(!ctype_alnum($val)) {
return $fail('Username is invalid. Username must be alpha-numeric and may contain dashes (-), periods (.) and underscores (_).');
}
$restricted = RestrictedNames::get();
if (in_array(strtolower($value), array_map('strtolower', $restricted))) {
return $fail('Username cannot be used.');
}
},
],
'name' => 'nullable|string|max:'.config('pixelfed.max_name_length'),
'email' => [
'required',
'string',
'email',
'max:255',
'unique:users',
function ($attribute, $value, $fail) {
$banned = EmailService::isBanned($value);
if($banned) {
return $fail('Email is invalid.');
}
},
],
'password' => 'required', 'password' => 'required',
'password_confirm' => 'required' 'password_confirm' => 'required'
]); ]);
@ -162,7 +211,7 @@ class AdminInviteController extends Controller
$invite->uses = $invite->uses + 1; $invite->uses = $invite->uses + 1;
event(new Registered($user = User::create([ event(new Registered($user = User::create([
'name' => $request->input('name') ?? $request->input('username'), 'name' => Purify::clean($request->input('name')) ?? $request->input('username'),
'username' => $request->input('username'), 'username' => $request->input('username'),
'email' => $request->input('email'), 'email' => $request->input('email'),
'password' => Hash::make($request->input('password')), 'password' => Hash::make($request->input('password')),

View file

@ -20,6 +20,8 @@ use App\User;
use App\Services\AccountService; use App\Services\AccountService;
use App\Services\StatusService; use App\Services\StatusService;
use App\Services\ProfileStatusService; use App\Services\ProfileStatusService;
use App\Services\PublicTimelineService;
use App\Services\NetworkTimelineService;
use App\Util\Lexer\RestrictedNames; use App\Util\Lexer\RestrictedNames;
use App\Services\EmailService; use App\Services\EmailService;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -29,6 +31,7 @@ use Mail;
use App\Mail\PasswordChange; use App\Mail\PasswordChange;
use App\Mail\ConfirmAppEmail; use App\Mail\ConfirmAppEmail;
use App\Http\Resources\StatusStateless; use App\Http\Resources\StatusStateless;
use App\Jobs\StatusPipeline\StatusDelete;
class ApiV1Dot1Controller extends Controller class ApiV1Dot1Controller extends Controller
{ {
@ -385,7 +388,6 @@ class ApiV1Dot1Controller extends Controller
return $this->json($res); return $this->json($res);
} }
/** /**
* GET /api/v1.1/accounts/apps-and-applications * GET /api/v1.1/accounts/apps-and-applications
* *
@ -595,7 +597,6 @@ class ApiV1Dot1Controller extends Controller
return [200]; return [200];
} }
public function unarchive(Request $request, $id) public function unarchive(Request $request, $id)
{ {
abort_if(!$request->user(), 403); abort_if(!$request->user(), 403);
@ -656,13 +657,115 @@ class ApiV1Dot1Controller extends Controller
->filter() ->filter()
->values(); ->values();
return ['place' => [ return [
'place' =>
[
'id' => $place->id, 'id' => $place->id,
'name' => $place->name, 'name' => $place->name,
'slug' => $place->slug, 'slug' => $place->slug,
'country' => $place->country, 'country' => $place->country,
'lat' => $place->lat, 'lat' => $place->lat,
'long' => $place->long 'long' => $place->long
], 'posts' => $posts]; ],
'posts' => $posts];
}
public function moderatePost(Request $request, $id)
{
abort_if(!$request->user(), 403);
abort_if($request->user()->is_admin != true, 403);
$this->validate($request, [
'action' => 'required|in:cw,mark-public,mark-unlisted,mark-private,mark-spammer,delete'
]);
$action = $request->input('action');
$status = Status::find($id);
if(!$status) {
return response()->json(['error' => 'Cannot find status'], 400);
}
if($status->uri == null) {
if($status->profile->user && $status->profile->user->is_admin) {
return response()->json(['error' => 'Cannot moderate admin accounts'], 400);
}
}
if($action == 'mark-spammer') {
$status->profile->update([
'unlisted' => true,
'cw' => true,
'no_autolink' => true
]);
Status::whereProfileId($status->profile_id)
->get()
->each(function($s) {
if(in_array($s->scope, ['public', 'unlisted'])) {
$s->scope = 'private';
$s->visibility = 'private';
}
$s->is_nsfw = true;
$s->save();
StatusService::del($s->id, true);
});
Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $status->profile_id);
Cache::forget('pf:bouncer_v0:recent_by_pid:' . $status->profile_id);
Cache::forget('admin-dash:reports:spam-count');
} else if ($action == 'cw') {
$state = $status->is_nsfw;
$status->is_nsfw = !$state;
$status->save();
StatusService::del($status->id);
} else if ($action == 'mark-public') {
$state = $status->scope;
$status->scope = 'public';
$status->visibility = 'public';
$status->save();
StatusService::del($status->id, true);
if($state !== 'public') {
if($status->uri) {
NetworkTimelineService::add($status->id);
} else {
PublicTimelineService::add($status->id);
}
}
} else if ($action == 'mark-unlisted') {
$state = $status->scope;
$status->scope = 'unlisted';
$status->visibility = 'unlisted';
$status->save();
StatusService::del($status->id);
if($state == 'public') {
PublicTimelineService::del($status->id);
NetworkTimelineService::del($status->id);
}
} else if ($action == 'mark-private') {
$state = $status->scope;
$status->scope = 'private';
$status->visibility = 'private';
$status->save();
StatusService::del($status->id);
if($state == 'public') {
PublicTimelineService::del($status->id);
NetworkTimelineService::del($status->id);
}
} else if ($action == 'delete') {
PublicTimelineService::del($status->id);
NetworkTimelineService::del($status->id);
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
Cache::forget('profile:status_count:' . $status->profile_id);
Cache::forget('profile:embed:' . $status->profile_id);
StatusService::del($status->id, true);
Cache::forget('profile:status_count:'.$status->profile_id);
StatusDelete::dispatch($status);
return [];
}
Cache::forget('_api:statuses:recent_9:'.$status->profile_id);
return StatusService::get($status->id, false);
} }
} }

View file

@ -4,6 +4,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\User; use App\User;
use Purify;
use App\Util\Lexer\RestrictedNames; use App\Util\Lexer\RestrictedNames;
use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
@ -157,7 +158,7 @@ class RegisterController extends Controller
} }
return User::create([ return User::create([
'name' => $data['name'], 'name' => Purify::clean($data['name']),
'username' => $data['username'], 'username' => $data['username'],
'email' => $data['email'], 'email' => $data['email'],
'password' => Hash::make($data['password']), 'password' => Hash::make($data['password']),

View file

@ -191,6 +191,7 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
}); });
Route::group(['prefix' => 'admin'], function() use($middleware) { Route::group(['prefix' => 'admin'], function() use($middleware) {
Route::post('moderate/post/{id}', 'Api\ApiV1Dot1Controller@moderatePost')->middleware($middleware);
Route::get('supported', 'Api\AdminApiController@supported')->middleware($middleware); Route::get('supported', 'Api\AdminApiController@supported')->middleware($middleware);
Route::get('stats', 'Api\AdminApiController@getStats')->middleware($middleware); Route::get('stats', 'Api\AdminApiController@getStats')->middleware($middleware);