Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
07/12/2014 01:26:36 AM (12 years ago)
Author:
boonebgorges
Message:

Overhaul access and visibility control for group tabs

Previously, access control to group tabs was handled in two ways:

  • for BP_Group_Extension tabs, the 'enable_nav_item' and 'visibility' provided some control over access to plugin developers, though it was inconsistent, buggy, and difficult to implement properly
  • for tabs provided by bp-groups, access to the tabs of non-public groups was controlled directly in the BP_Groups_Component::setup_globals() method

Aside from being unclear for developers, this technique for controlling access
was also inflexible. For non-public groups, tab access was hardcoded and
handled before BP_Group_Extension plugins even had a chance to load. As a
result, it was essentially impossible to add public tabs to non-public groups
(among other non-standard customizations).

The current changeset comprises a number of changes that make tab access more
consistent and flexible:

  • Access control is moved to the new bp_groups_group_access_protection() function. This function has the necessary filters to customize access protection in arbitrary ways. And because it loads at 'bp_actions' - just before the page begins to render - all extensions have had a chance to load and register themselves with the desired access settings.
  • The 'visibility' and 'enable_nav_item' properties of BP_Group_Extension are phased out in favor of 'access' and 'show_tab' params. 'access' controls who can visit the tab, while 'show_tab' controls who can see the item in the navigation. These new properties have intelligent defaults (based on the privacy level of the group), but can be overridden with a number of custom settings: 'admin', 'mod', 'member', 'loggedin', 'anyone', or 'noone'. Backward compatibility is maintained, so that existing BP_Group_Extension plugins that use enable_nav_item or visibility will continue to work as before.

Fixes #4785

Props boonebgorges, dcavins, imath

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-groups/bp-groups-classes.php

    r8557 r8605  
    28812881
    28822882        /**
     2883         * Raw config params, as passed by the extending class.
     2884         *
     2885         * @since BuddyPress (2.1.0)
     2886         * @var array
     2887         */
     2888        public $params_raw = array();
     2889
     2890        /**
    28832891         * The ID of the current group.
    28842892         *
     
    29222930         */
    29232931        public $enable_nav_item = true;
     2932
     2933        /**
     2934         * Whether the current user should see the navigation item.
     2935         *
     2936         * @since BuddyPress (2.1.0)
     2937         * @var bool
     2938         */
     2939        public $user_can_see_nav_item;
     2940
     2941        /**
     2942         * Whether the current user can visit the tab.
     2943         *
     2944         * @since BuddyPress (2.1.0)
     2945         * @var bool
     2946         */
     2947        public $user_can_visit;
    29242948
    29252949        /**
     
    30613085         */
    30623086        public function init( $args = array() ) {
     3087                // Store the raw arguments
     3088                $this->params_raw = $args;
    30633089
    30643090                // Before this init() method was introduced, plugins were
     
    30813107                        'template_file'     => $this->template_file,
    30823108                        'screens'           => $this->get_default_screens(),
     3109                        'access'            => null,
     3110                        'show_tab'          => null,
    30833111                ) );
    30843112
     
    31233151                // Configure 'screens': create, admin, and edit contexts
    31243152                $this->setup_screens();
     3153
     3154                // Configure access-related settings
     3155                $this->setup_access_settings();
    31253156
    31263157                // Mirror configuration data so it's accessible to plugins
     
    32423273        }
    32433274
     3275        /**
     3276         * Set up access-related settings for this extension.
     3277         *
     3278         * @since BuddyPress (2.1.0)
     3279         */
     3280        protected function setup_access_settings() {
     3281                // Backward compatibility
     3282                if ( isset( $this->params['enable_nav_item'] ) ) {
     3283                        $this->enable_nav_item = (bool) $this->params['enable_nav_item'];
     3284                }
     3285
     3286                // Tab Access
     3287                $this->user_can_visit = false;
     3288
     3289                // Backward compatibility for components that do not provide
     3290                // explicit 'access' parameter
     3291                if ( empty( $this->params['access'] ) ) {
     3292                        if ( false === $this->enable_nav_item ) {
     3293                                $this->params['access'] = 'noone';
     3294                        } else {
     3295                                $group = groups_get_group( array(
     3296                                        'group_id' => $this->group_id,
     3297                                ) );
     3298
     3299                                if ( ! empty( $group->status ) && 'public' === $group->status ) {
     3300                                        // Tabs in public groups are accessible to anyone by default
     3301                                        $this->params['access'] = 'anyone';
     3302                                } else {
     3303                                        // All other groups have members-only as the default
     3304                                        $this->params['access'] = 'member';
     3305                                }
     3306                        }
     3307                }
     3308
     3309                // Parse multiple access conditions into an array
     3310                $access_conditions = $this->params['access'];
     3311                if ( ! is_array( $access_conditions ) ) {
     3312                        $access_conditions = explode( ',', $access_conditions );
     3313                }
     3314
     3315                // If the current user meets at least one condition, the
     3316                // get access
     3317                foreach ( $access_conditions as $access_condition ) {
     3318                        if ( $this->user_meets_access_condition( $access_condition ) ) {
     3319                                $this->user_can_visit = true;
     3320                                break;
     3321                        }
     3322                }
     3323
     3324                // Tab Visibility
     3325                $this->user_can_see_nav_item = false;
     3326
     3327                // Backward compatibility for components that do not provide
     3328                // explicit 'show_tab' parameter
     3329                if ( empty( $this->params['show_tab'] ) ) {
     3330                        if ( false === $this->params['enable_nav_item'] ) {
     3331                                // enable_nav_item is only false if it's been
     3332                                // defined explicitly as such in the
     3333                                // constructor. So we always trust this value
     3334                                $this->params['show_tab'] = 'noone';
     3335
     3336                        } else if ( isset( $this->params_raw['enable_nav_item'] ) || isset( $this->params_raw['visibility'] ) ) {
     3337                                // If enable_nav_item or visibility is passed,
     3338                                // we assume this  is a legacy extension.
     3339                                // Legacy behavior is that enable_nav_item=true +
     3340                                // visibility=private implies members-only
     3341                                if ( 'public' !== $this->visibility ) {
     3342                                        $this->params['show_tab'] = 'member';
     3343                                } else {
     3344                                        $this->params['show_tab'] = 'anyone';
     3345                                }
     3346
     3347                        } else {
     3348                                // No show_tab or enable_nav_item value is
     3349                                // available, so match the value of 'access'
     3350                                $this->params['show_tab'] = $this->params['access'];
     3351                        }
     3352                }
     3353
     3354                // Parse multiple access conditions into an array
     3355                $access_conditions = $this->params['show_tab'];
     3356                if ( ! is_array( $access_conditions ) ) {
     3357                        $access_conditions = explode( ',', $access_conditions );
     3358                }
     3359
     3360                // If the current user meets at least one condition, the
     3361                // get access
     3362                foreach ( $access_conditions as $access_condition ) {
     3363                        if ( $this->user_meets_access_condition( $access_condition ) ) {
     3364                                $this->user_can_see_nav_item = true;
     3365                                break;
     3366                        }
     3367                }
     3368        }
     3369
     3370        /**
     3371         * Check whether the current user meets an access condition.
     3372         *
     3373         * @param string $access_condition 'anyone', 'loggedin', 'member',
     3374         *        'mod', 'admin' or 'noone'.
     3375         * @return bool
     3376         */
     3377        protected function user_meets_access_condition( $access_condition ) {
     3378                $group = groups_get_group( array(
     3379                        'group_id' => $this->group_id,
     3380                ) );
     3381
     3382                switch ( $access_condition ) {
     3383                        case 'admin' :
     3384                                $meets_condition = groups_is_user_admin( bp_loggedin_user_id(), $this->group_id );
     3385                                break;
     3386
     3387                        case 'mod' :
     3388                                $meets_condition = groups_is_user_mod( bp_loggedin_user_id(), $this->group_id );
     3389                                break;
     3390
     3391                        case 'member' :
     3392                                $meets_condition = groups_is_user_member( bp_loggedin_user_id(), $this->group_id );
     3393                                break;
     3394
     3395                        case 'loggedin' :
     3396                                $meets_condition = is_user_logged_in();
     3397                                break;
     3398
     3399                        case 'noone' :
     3400                                $meets_condition = false;
     3401                                break;
     3402
     3403                        case 'anyone' :
     3404                        default :
     3405                                $meets_condition = true;
     3406                                break;
     3407                }
     3408
     3409                return $meets_condition;
     3410        }
     3411
    32443412        /** Display ***********************************************************/
    32453413
     
    32563424                }
    32573425
    3258                 // Bail if the current user doesn't have access
     3426                // Backward compatibility only
    32593427                if ( ( 'public' !== $this->visibility ) && ! buddypress()->groups->current_group->user_has_access ) {
    32603428                        return;
    32613429                }
    32623430
    3263                 if ( true === $this->enable_nav_item ) {
     3431                $user_can_see_nav_item = $this->user_can_see_nav_item();
     3432
     3433                if ( $user_can_see_nav_item ) {
     3434                        $group_permalink = bp_get_group_permalink( groups_get_current_group() );
     3435
    32643436                        bp_core_new_subnav_item( array(
    32653437                                'name'            => ! $this->nav_item_name ? $this->name : $this->nav_item_name,
    32663438                                'slug'            => $this->slug,
    32673439                                'parent_slug'     => bp_get_current_group_slug(),
    3268                                 'parent_url'      => bp_get_group_permalink( groups_get_current_group() ),
     3440                                'parent_url'      => $group_permalink,
    32693441                                'position'        => $this->nav_item_position,
    32703442                                'item_css_id'     => 'nav-' . $this->slug,
    32713443                                'screen_function' => array( &$this, '_display_hook' ),
    3272                                 'user_has_access' => $this->enable_nav_item
     3444                                'user_has_access' => $user_can_see_nav_item,
     3445                                'no_access_url'   => $group_permalink,
    32733446                        ) );
    32743447
    32753448                        // When we are viewing the extension display page, set the title and options title
    32763449                        if ( bp_is_current_action( $this->slug ) ) {
     3450                                add_filter( 'bp_group_user_has_access',   array( $this, 'group_access_protection' ), 10, 2 );
    32773451                                add_action( 'bp_template_content_header', create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
    32783452                                add_action( 'bp_template_title',          create_function( '', 'echo "' . esc_attr( $this->name ) . '";' ) );
     
    32933467                bp_core_load_template( apply_filters( 'bp_core_template_plugin', $this->template_file ) );
    32943468        }
     3469
     3470        /**
     3471         * Determine whether the current user should see this nav tab.
     3472         *
     3473         * Note that this controls only the display of the navigation item.
     3474         * Access to the tab is controlled by the user_can_visit() check.
     3475         *
     3476         * @since BuddyPress (2.1.0)
     3477         *
     3478         * @return bool
     3479         */
     3480        public function user_can_see_nav_item( $user_can_see_nav_item = false ) {
     3481                if ( 'noone' !== $this->params['show_tab'] && current_user_can( 'bp_moderate' ) ) {
     3482                        return true;
     3483                }
     3484
     3485                return $this->user_can_see_nav_item;
     3486        }
     3487
     3488        /**
     3489         * Determine whether the current user has access to visit this tab.
     3490         *
     3491         * @since BuddyPress (2.1.0)
     3492         *
     3493         * @return bool
     3494         */
     3495        public function user_can_visit( $user_can_visit = false ) {
     3496                if ( 'noone' !== $this->params['access'] && current_user_can( 'bp_moderate' ) ) {
     3497                        return true;
     3498                }
     3499
     3500                return $this->user_can_visit;
     3501        }
     3502
     3503        /**
     3504         * Filter the access check in bp_groups_group_access_protection() for this extension.
     3505         *
     3506         * Note that $no_access_args is passed by reference, as there are some
     3507         * circumstances where the bp_core_no_access() arguments need to be
     3508         * modified before the redirect takes place.
     3509         *
     3510         * @since BuddyPress (2.1.0)
     3511         *
     3512         * @param bool $user_can_visit
     3513         * @param array $no_access_args
     3514         * @return bool
     3515         */
     3516        public function group_access_protection( $user_can_visit, &$no_access_args ) {
     3517                $user_can_visit = $this->user_can_visit();
     3518
     3519                if ( ! $user_can_visit && is_user_logged_in() ) {
     3520                        $current_group = groups_get_group( array(
     3521                                'group_id' => $this->group_id,
     3522                        ) );
     3523
     3524                        $no_access_args['message'] = __( 'You do not have access to this content.', 'buddypress' );
     3525                        $no_access_args['root'] = bp_get_group_permalink( $current_group ) . 'home/';
     3526                        $no_access_args['redirect'] = false;
     3527                }
     3528
     3529                return $user_can_visit;
     3530        }
     3531
    32953532
    32963533        /** Create ************************************************************/
Note: See TracChangeset for help on using the changeset viewer.