feat(permission): add the no one permission

One thing that has been very frustrating while developing extensions is
that you cannot easily create a feature that you would like to allow
disabling through the permission grid.

This Proof of Concept PR is a question, whether I'm the only one running
into this limitation for Flarum.

It does:

- introduce a fake permission, similar to Guest
- removes the whole permission entry from the db when selected
- restores the permission visually on the frontend

It has to:

- confirm admins also cannot use the permission if selected
- not break v1.x functionality or be moved to v2.0
- appeal to core and community
This commit is contained in:
Daniël Klabbers 2023-03-26 10:03:09 +02:00
parent bddc9d96f2
commit 7dcbbf29ab
11 changed files with 69177 additions and 1123 deletions

30362
framework/core/js/dist/admin.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

37513
framework/core/js/dist/forum.js generated vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -48,15 +48,18 @@ export default class PermissionDropdown<CustomAttrs extends IPermissionDropdownA
view(vnode: Mithril.Vnode<CustomAttrs, this>) {
const children = [];
let groupIds = app.data.permissions[this.attrs.permission] || [];
let groupIds = app.data.permissions[this.attrs.permission] || [Group.NO_ONE_ID];
groupIds = filterByRequiredPermissions(groupIds, this.attrs.permission);
const no_one = groupIds.includes(Group.NO_ONE_ID);
const everyone = groupIds.includes(Group.GUEST_ID);
const members = groupIds.includes(Group.MEMBER_ID);
const adminGroup = app.store.getById<Group>('groups', Group.ADMINISTRATOR_ID)!;
if (everyone) {
if (no_one) {
this.attrs.label = Badge.component({ icon: 'fas fa-user-slash' });
} else if (everyone) {
this.attrs.label = Badge.component({ icon: 'fas fa-globe' });
} else if (members) {
this.attrs.label = Badge.component({ icon: 'fas fa-user' });
@ -65,6 +68,18 @@ export default class PermissionDropdown<CustomAttrs extends IPermissionDropdownA
}
if (this.showing) {
if (this.attrs.allowNoOne) {
children.push(
Button.component(
{
icon: no_one ? 'fas fa-check' : true,
onclick: () => this.save([Group.NO_ONE_ID]),
disabled: this.isGroupDisabled(Group.NO_ONE_ID),
},
[Badge.component({ icon: 'fas fa-user-slash' }), ' ', app.translator.trans('core.admin.permissions_controls.no_one_button')]
)
);
}
if (this.attrs.allowGuest) {
children.push(
Button.component(

View File

@ -12,6 +12,7 @@ export interface PermissionConfig {
icon: string;
label: Mithril.Children;
allowGuest?: boolean;
allowNoOne?: boolean;
}
export interface PermissionSetting {
@ -435,6 +436,7 @@ export default class PermissionGrid<CustomAttrs extends IPermissionGridAttrs = I
return PermissionDropdown.component({
permission: item.permission,
allowGuest: item.allowGuest,
allowNoOne: item.allowNoOne,
});
}

View File

@ -1,6 +1,7 @@
import Model from '../Model';
export default class Group extends Model {
static NO_ONE_ID = '-1';
static ADMINISTRATOR_ID = '1';
static GUEST_ID = '2';
static MEMBER_ID = '3';

View File

@ -235,6 +235,7 @@ core:
members_button: => core.group.members
signup_closed_button: Closed
signup_open_button: Open
no_one_button: No one
# These translations are used generically in setting fields.
settings:

View File

@ -9,6 +9,7 @@
namespace Flarum\Api\Controller;
use Flarum\Group\Group;
use Flarum\Group\Permission;
use Flarum\Http\RequestUtil;
use Illuminate\Support\Arr;
@ -32,6 +33,11 @@ class SetPermissionController implements RequestHandlerInterface
Permission::where('permission', $permission)->delete();
// Permission set to no one.
if (count($groupIds) === 1 && intval($groupIds[0]) === Group::NO_ONE_ID) {
return new EmptyResponse(204);
}
Permission::insert(array_map(function ($groupId) use ($permission) {
return [
'permission' => $permission,

View File

@ -32,6 +32,11 @@ class Group extends AbstractModel
use EventGeneratorTrait;
use ScopeVisibilityTrait;
/**
* The temporary ID for when no one can do something.
*/
const NO_ONE_ID = -1;
/**
* The ID of the administrator group.
*/

2387
yarn.lock

File diff suppressed because it is too large Load Diff