[buddypress-trac] [BuddyPress Trac] #7176: Implement user capabilities for Activity component
buddypress-trac
noreply at wordpress.org
Tue Aug 30 03:47:09 UTC 2016
#7176: Implement user capabilities for Activity component
-------------------------+-----------------------------
Reporter: DJPaul | Owner:
Type: enhancement | Status: new
Priority: normal | Milestone: Future Release
Component: Activity | Version:
Severity: normal | Resolution:
Keywords: |
-------------------------+-----------------------------
Comment (by boonebgorges):
I spent some time looking at this and hacking around with
[attachment:7176.01.patch] and with a patch of my own.
WP's Roles system is quite flawed, and I am not eager to use it. Just
thinking about the activation/deactivation and other database nonsense
associated with roles makes me cringe.
However, Roles plays a critical part in the way that WP's capabilities
system works:
a. Most permissions checks are "derived", which means that they're mapped
to "primitive" caps.
b. "Primitive" caps come in packages called "roles" - things like
"Subscriber", "Editor", etc.
c. Roles are stored in the database as serialized arrays of their
associated caps.
d. Users are associated with roles based on "capabilities" (bad name!)
keys stored in usermeta.
Without Roles, our capability mapping system would have to map to a
*WordPress* primitive role - specifically, a role that we can guarantee
that all users will have. We already do this in BP, with `'exist'`
https://buddypress.trac.wordpress.org/browser/tags/2.6.0/src/bp-xprofile
/bp-xprofile-caps.php#L13 (we could use `read` in most cases, but here we
needed to cover non-logged-in users). The problem with this strategy is
that the only way for plugins to modify the behavior is to filter
`map_meta_cap`, and then reproduce all of the logic for a given capability
in order to grant it in a different way. You can't simply grant or revoke
a cap in order to prevent a user from doing something, since everything
would map to `exist` or `read`, which you can't revoke for obvious
reasons.
(bbPress, which does interesting things with this limited system, works
around the fact that you can only have two layers of caps - primitive and
derived - by doing `user_can()` checks inside of the `map_meta_cap`
callback. This is clever, but in my experience it can cause performance
issues and even "nesting limit reached" PHP fatal errors.)
For this reason, I think we should keep the concept of Roles, even if we
decide not to use the full-fledged, stored-in-the-database version that WP
has. Our roles might be defined in (pseudo)code like this:
{{{
'member' => array( 'bp_edit_activities', 'bp_create_activities' ... )
'admin' => 'member' + array( 'bp_edit_others_activities',
'bp_delete_others_activities' ... )
}}}
We hardcode our default roles, and allow them to be filtered, so that new
roles can be added or existing ones can be modified by plugins. Our
`map_meta_cap()` function will follow WP by mapping derivative caps to
primary ones:
{{{
$caps = array();
...
case 'bp_edit_activity' :
...
if ( $activity->user_id === $user_id ) {
$caps[] = 'bp_edit_activities';
} else {
$caps[] = 'bp_edit_others_activities';
}
break;
...
}}}
Users can be granted a "role" dynamically, using the `user_has_cap`
filter:
{{{
function bp_grant_user_caps( $allcaps, $caps, $args, WP_User $user ) {
$user_role = bp_get_user_role( $user->ID );
$user_caps = bp_get_role_caps( $role );
$allcaps = array_merge( $allcaps, $user_caps );
return $allcaps;
}
add_filter( 'user_has_cap', 'bp_grant_user_caps', 10, 4 );
}}}
I can see a couple different kinds of plugins that might be built with
this sort of system:
1. Create a "moderator" role that can edit others' activity, but not
delete:
{{{
add_filter( 'bp_get_roles', function( $roles ) {
$roles['mod'] = $roles['member'] + array( 'bp_edit_others_activities'
);
return $roles;
} );
}}}
2. Prevent users from being able to delete their activities:
{{{
add_filter( 'bp_get_roles', function( $roles ) {
unset( $roles['member']['bp_delete_activities'] );
return $roles;
} );
}}}
It's only when you're doing something very advanced - say, revoking a
given cap only when an activity item meets a given criteria - that you'd
need to filter `map_meta_cap`.
I think this is a decent compromise. It keeps the developer-facing ease-
of-use of the Roles system, without mucking around with the database. The
one big downside of not doing database integration is that we aren't
automatically compatible with existing Role Editor plugins.
Obviously there's lots of non-working and naive pseudocode above. We may
want components to register their own primitive caps, or other such
niceties. But I think that I've given a rough sketch of how the system
might work.
@DJPaul Does this seem like a reasonable approach? @r-a-y @johnjamesjacoby
it would be helpful to have your general thoughts too, given that you've
both done lots of work with custom role/cap stuff. If we like the
direction, I can take the next round of iteration on
[attachment:7176.01.patch] to flesh out some of the details as I envision
them.
--
Ticket URL: <https://buddypress.trac.wordpress.org/ticket/7176#comment:8>
BuddyPress Trac <http://buddypress.org/>
BuddyPress Trac
More information about the buddypress-trac
mailing list