From 7dbdbf15a5fcfcd11726b4f3fabffa53cf08bb72 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 27 Dec 2023 02:51:47 -0700 Subject: [PATCH] Add Roles & Parental Controls --- app/Http/Controllers/Api/ApiV1Controller.php | 10 ++ app/Http/Controllers/UserRolesController.php | 10 ++ app/Models/UserRoles.php | 23 ++++ app/Providers/AuthServiceProvider.php | 2 +- app/Services/UserRoleService.php | 111 ++++++++++++++++++ ...3_12_27_081801_create_user_roles_table.php | 30 +++++ ...27_082024_add_has_roles_to_users_table.php | 28 +++++ 7 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/UserRolesController.php create mode 100644 app/Models/UserRoles.php create mode 100644 app/Services/UserRoleService.php create mode 100644 database/migrations/2023_12_27_081801_create_user_roles_table.php create mode 100644 database/migrations/2023_12_27_082024_add_has_roles_to_users_table.php diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 798d9ee55..6f314e0b3 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -98,6 +98,7 @@ use App\Jobs\MediaPipeline\MediaSyncLicensePipeline; use App\Services\DiscoverService; use App\Services\CustomEmojiService; use App\Services\MarkerService; +use App\Services\UserRoleService; use App\Models\Conversation; use App\Jobs\FollowPipeline\FollowAcceptPipeline; use App\Jobs\FollowPipeline\FollowRejectPipeline; @@ -1623,6 +1624,8 @@ class ApiV1Controller extends Controller ]); $user = $request->user(); + abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action'); + AccountService::setLastActive($user->id); if($user->last_active_at == null) { @@ -1792,6 +1795,7 @@ class ApiV1Controller extends Controller abort_if(!$request->user(), 403); $user = $request->user(); + abort_if($user->has_roles && !UserRoleService::can('can-post', $user->id), 403, 'Invalid permissions for this action'); AccountService::setLastActive($user->id); $media = Media::whereUserId($user->id) @@ -1831,6 +1835,7 @@ class ApiV1Controller extends Controller ]); $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) { return []; @@ -2419,8 +2424,13 @@ class ApiV1Controller extends Controller $max = $request->input('max_id'); $limit = $request->input('limit') ?? 20; $user = $request->user(); + $remote = $request->has('remote'); $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) : []; AccountService::setLastActive($user->id); $domainBlocks = UserFilterService::domainBlocks($user->profile_id); diff --git a/app/Http/Controllers/UserRolesController.php b/app/Http/Controllers/UserRolesController.php new file mode 100644 index 000000000..dbd34d0da --- /dev/null +++ b/app/Http/Controllers/UserRolesController.php @@ -0,0 +1,10 @@ + 'array' + ]; + + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 0ec8c1895..8e1a6a98d 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -14,7 +14,7 @@ class AuthServiceProvider extends ServiceProvider * @var array */ protected $policies = [ - 'App\Model' => 'App\Policies\ModelPolicy', + // 'App\Model' => 'App\Policies\ModelPolicy', ]; /** diff --git a/app/Services/UserRoleService.php b/app/Services/UserRoleService.php new file mode 100644 index 000000000..fef5356c2 --- /dev/null +++ b/app/Services/UserRoleService.php @@ -0,0 +1,111 @@ +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-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' + ], + ]; + } +} diff --git a/database/migrations/2023_12_27_081801_create_user_roles_table.php b/database/migrations/2023_12_27_081801_create_user_roles_table.php new file mode 100644 index 000000000..4e6af18d0 --- /dev/null +++ b/database/migrations/2023_12_27_081801_create_user_roles_table.php @@ -0,0 +1,30 @@ +id(); + $table->unsignedBigInteger('profile_id')->unique()->index(); + $table->unsignedInteger('user_id')->unique()->index(); + $table->json('roles')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('user_roles'); + } +}; diff --git a/database/migrations/2023_12_27_082024_add_has_roles_to_users_table.php b/database/migrations/2023_12_27_082024_add_has_roles_to_users_table.php new file mode 100644 index 000000000..c60b81deb --- /dev/null +++ b/database/migrations/2023_12_27_082024_add_has_roles_to_users_table.php @@ -0,0 +1,28 @@ +boolean('has_roles')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('has_roles'); + }); + } +};