mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-22 14:31:26 +00:00
Merge pull request #4843 from pixelfed/staging
Add Roles & Parental Controls
This commit is contained in:
commit
5b4214cb80
8 changed files with 253 additions and 1 deletions
|
@ -98,6 +98,7 @@ use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
|
||||||
use App\Services\DiscoverService;
|
use App\Services\DiscoverService;
|
||||||
use App\Services\CustomEmojiService;
|
use App\Services\CustomEmojiService;
|
||||||
use App\Services\MarkerService;
|
use App\Services\MarkerService;
|
||||||
|
use App\Services\UserRoleService;
|
||||||
use App\Models\Conversation;
|
use App\Models\Conversation;
|
||||||
use App\Jobs\FollowPipeline\FollowAcceptPipeline;
|
use App\Jobs\FollowPipeline\FollowAcceptPipeline;
|
||||||
use App\Jobs\FollowPipeline\FollowRejectPipeline;
|
use App\Jobs\FollowPipeline\FollowRejectPipeline;
|
||||||
|
@ -1244,6 +1245,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-like', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
|
|
||||||
|
@ -1305,6 +1307,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-like', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
|
|
||||||
|
@ -1623,6 +1626,8 @@ class ApiV1Controller extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
|
|
||||||
if($user->last_active_at == null) {
|
if($user->last_active_at == null) {
|
||||||
|
@ -1792,6 +1797,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action');
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
|
|
||||||
$media = Media::whereUserId($user->id)
|
$media = Media::whereUserId($user->id)
|
||||||
|
@ -1831,6 +1837,7 @@ class ApiV1Controller extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
if($user->last_active_at == null) {
|
if($user->last_active_at == null) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -2419,8 +2426,13 @@ class ApiV1Controller extends Controller
|
||||||
$max = $request->input('max_id');
|
$max = $request->input('max_id');
|
||||||
$limit = $request->input('limit') ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
|
||||||
$remote = $request->has('remote');
|
$remote = $request->has('remote');
|
||||||
$local = $request->has('local');
|
$local = $request->has('local');
|
||||||
|
$userRoleKey = $remote ? 'can-view-network-feed' : 'can-view-public-feed';
|
||||||
|
if($user->has_roles && !UserRoleService::can($userRoleKey, $user->id)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
$domainBlocks = UserFilterService::domainBlocks($user->profile_id);
|
$domainBlocks = UserFilterService::domainBlocks($user->profile_id);
|
||||||
|
@ -3165,6 +3177,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action');
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
$status = Status::whereScope('public')->findOrFail($id);
|
$status = Status::whereScope('public')->findOrFail($id);
|
||||||
|
|
||||||
|
@ -3212,6 +3225,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action');
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
$status = Status::whereScope('public')->findOrFail($id);
|
$status = Status::whereScope('public')->findOrFail($id);
|
||||||
|
|
||||||
|
@ -3262,6 +3276,13 @@ class ApiV1Controller extends Controller
|
||||||
'_pe' => 'sometimes'
|
'_pe' => 'sometimes'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$user = $request->user();
|
||||||
|
abort_if(
|
||||||
|
$user->has_roles && !UserRoleService::can('can-view-hashtag-feed', $user->id),
|
||||||
|
403,
|
||||||
|
'Invalid permissions for this action'
|
||||||
|
);
|
||||||
|
|
||||||
if(config('database.default') === 'pgsql') {
|
if(config('database.default') === 'pgsql') {
|
||||||
$tag = Hashtag::where('name', 'ilike', $hashtag)
|
$tag = Hashtag::where('name', 'ilike', $hashtag)
|
||||||
->orWhere('slug', 'ilike', $hashtag)
|
->orWhere('slug', 'ilike', $hashtag)
|
||||||
|
|
|
@ -54,6 +54,7 @@ use App\Util\Lexer\Autolink;
|
||||||
use App\Util\Lexer\Extractor;
|
use App\Util\Lexer\Extractor;
|
||||||
use App\Util\Media\License;
|
use App\Util\Media\License;
|
||||||
use Image;
|
use Image;
|
||||||
|
use App\Services\UserRoleService;
|
||||||
|
|
||||||
class ComposeController extends Controller
|
class ComposeController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -92,6 +93,7 @@ class ComposeController extends Controller
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$profile = $user->profile;
|
$profile = $user->profile;
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
$limitKey = 'compose:rate-limit:media-upload:' . $user->id;
|
$limitKey = 'compose:rate-limit:media-upload:' . $user->id;
|
||||||
$limitTtl = now()->addMinutes(15);
|
$limitTtl = now()->addMinutes(15);
|
||||||
|
@ -184,6 +186,7 @@ class ComposeController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action');
|
||||||
|
|
||||||
$limitKey = 'compose:rate-limit:media-updates:' . $user->id;
|
$limitKey = 'compose:rate-limit:media-updates:' . $user->id;
|
||||||
$limitTtl = now()->addMinutes(15);
|
$limitTtl = now()->addMinutes(15);
|
||||||
|
|
23
app/Http/Controllers/UserRolesController.php
Normal file
23
app/Http/Controllers/UserRolesController.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Services\UserRoleService;
|
||||||
|
|
||||||
|
class UserRolesController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware('auth');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoles(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'id' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return UserRoleService::getRoles($request->user()->id);
|
||||||
|
}
|
||||||
|
}
|
23
app/Models/UserRoles.php
Normal file
23
app/Models/UserRoles.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use App\User;
|
||||||
|
|
||||||
|
class UserRoles extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'roles' => 'array'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ class AuthServiceProvider extends ServiceProvider
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $policies = [
|
protected $policies = [
|
||||||
'App\Model' => 'App\Policies\ModelPolicy',
|
// 'App\Model' => 'App\Policies\ModelPolicy',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
119
app/Services/UserRoleService.php
Normal file
119
app/Services/UserRoleService.php
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\UserRoles;
|
||||||
|
|
||||||
|
class UserRoleService
|
||||||
|
{
|
||||||
|
public static function can($action, $id, $useDefaultFallback = true)
|
||||||
|
{
|
||||||
|
$default = self::defaultRoles();
|
||||||
|
$roles = self::get($id);
|
||||||
|
return
|
||||||
|
in_array($action, array_keys($roles)) ?
|
||||||
|
$roles[$action] :
|
||||||
|
(
|
||||||
|
$useDefaultFallback ?
|
||||||
|
$default[$action] :
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($id)
|
||||||
|
{
|
||||||
|
if($roles = UserRoles::whereUserId($id)->first()) {
|
||||||
|
return $roles->roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::defaultRoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function roleKeys()
|
||||||
|
{
|
||||||
|
return array_keys(self::defaultRoles());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function defaultRoles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'account-force-private' => true,
|
||||||
|
'account-ignore-follow-requests' => true,
|
||||||
|
|
||||||
|
'can-view-public-feed' => true,
|
||||||
|
'can-view-network-feed' => true,
|
||||||
|
'can-view-discover' => true,
|
||||||
|
'can-view-hashtag-feed' => false,
|
||||||
|
|
||||||
|
'can-post' => true,
|
||||||
|
'can-comment' => true,
|
||||||
|
'can-like' => true,
|
||||||
|
'can-share' => true,
|
||||||
|
|
||||||
|
'can-follow' => false,
|
||||||
|
'can-make-public' => false,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRoles($id)
|
||||||
|
{
|
||||||
|
$myRoles = self::get($id);
|
||||||
|
$roleData = collect(self::roleData())
|
||||||
|
->map(function($role, $k) use($myRoles) {
|
||||||
|
$role['value'] = $myRoles[$k];
|
||||||
|
return $role;
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
return $roleData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function roleData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'account-force-private' => [
|
||||||
|
'title' => 'Force Private Account',
|
||||||
|
'action' => 'Prevent changing account from private'
|
||||||
|
],
|
||||||
|
'account-ignore-follow-requests' => [
|
||||||
|
'title' => 'Ignore Follow Requests',
|
||||||
|
'action' => 'Hide follow requests and associated notifications'
|
||||||
|
],
|
||||||
|
'can-view-public-feed' => [
|
||||||
|
'title' => 'Hide Public Feed',
|
||||||
|
'action' => 'Hide the public feed timeline'
|
||||||
|
],
|
||||||
|
'can-view-network-feed' => [
|
||||||
|
'title' => 'Hide Network Feed',
|
||||||
|
'action' => 'Hide the network feed timeline'
|
||||||
|
],
|
||||||
|
'can-view-discover' => [
|
||||||
|
'title' => 'Hide Discover',
|
||||||
|
'action' => 'Hide the discover feature'
|
||||||
|
],
|
||||||
|
'can-post' => [
|
||||||
|
'title' => 'Can post',
|
||||||
|
'action' => 'Allows new posts to be shared'
|
||||||
|
],
|
||||||
|
'can-comment' => [
|
||||||
|
'title' => 'Can comment',
|
||||||
|
'action' => 'Allows new comments to be posted'
|
||||||
|
],
|
||||||
|
'can-like' => [
|
||||||
|
'title' => 'Can Like',
|
||||||
|
'action' => 'Allows the ability to like posts and comments'
|
||||||
|
],
|
||||||
|
'can-share' => [
|
||||||
|
'title' => 'Can Share',
|
||||||
|
'action' => 'Allows the ability to share posts and comments'
|
||||||
|
],
|
||||||
|
'can-follow' => [
|
||||||
|
'title' => 'Can Follow',
|
||||||
|
'action' => 'Allows the ability to follow accounts'
|
||||||
|
],
|
||||||
|
'can-make-public' => [
|
||||||
|
'title' => 'Can make account public',
|
||||||
|
'action' => 'Allows the ability to make account public'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('user_roles', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('profile_id')->unique()->index();
|
||||||
|
$table->unsignedInteger('user_id')->unique()->index();
|
||||||
|
$table->json('roles')->nullable();
|
||||||
|
$table->json('meta')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('user_roles');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->boolean('has_roles')->default(false);
|
||||||
|
$table->unsignedInteger('parent_id')->nullable();
|
||||||
|
$table->tinyInteger('role_id')->unsigned()->nullable()->index();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('has_roles');
|
||||||
|
$table->dropColumn('parent_id');
|
||||||
|
$table->dropColumn('role_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue