function agp_array_flatten($arr_md, $go_deep = true)
{
    //flattens multi-dim arrays (destroys keys)
    $arr_flat = array();
    if (!is_array($arr_md)) {
        return $arr_flat;
    }
    foreach ($arr_md as $element) {
        if (is_array($element)) {
            if ($go_deep) {
                $arr_flat = array_merge($arr_flat, agp_array_flatten($element));
            } else {
                $arr_flat = array_merge($arr_flat, $element);
            }
        } else {
            array_push($arr_flat, $element);
        }
    }
    return $arr_flat;
}
 function identify_protected_posts($attachment_id = 0, $attachments = false, $cols = '', $args = array())
 {
     $defaults = array('use_object_restrictions' => true, 'use_term_restrictions' => true, 'use_private_status' => true, 'guid' => '');
     $args = array_merge($defaults, (array) $args);
     extract($args);
     global $wpdb, $scoper;
     if (!isset($scoper) || is_null($scoper)) {
         scoper_get_init_options();
         scoper_init();
     }
     if (empty($scoper->taxonomies)) {
         $scoper->load_config();
     }
     $restricted_roles = array();
     $unrestricted_roles = array();
     // TODO: also protect uploads based on restriction of other taxonomies
     $restricted_terms = array();
     $restricted_objects = array();
     $term_restriction_clause = '';
     $object_restriction_clause = '';
     $limit_clause = '';
     $unattached_clause = '';
     global $scoper;
     $reader_roles = array();
     foreach ($scoper->role_defs->role_caps as $role_handle => $role_caps) {
         $caps_by_op = $scoper->cap_defs->organize_caps_by_op(array_keys($role_caps));
         if (count($caps_by_op) == 1 && 'read' == key($caps_by_op)) {
             $reader_roles[] = $role_handle;
         }
     }
     $role_clause = "AND rs.role_name IN ('" . implode("','", scoper_role_handles_to_names($reader_roles)) . "')";
     //if ( $use_private_status )
     //	$role_clause = ( 'rs' == SCOPER_ROLE_TYPE ) ? "AND rs.role_name IN ('post_reader', 'page_reader')" : '';	// if also checking for private status, don't need to check for restriction of private_reader roles
     //else
     //	$role_clause = ( 'rs' == SCOPER_ROLE_TYPE ) ? "AND rs.role_name IN ('post_reader', 'page_reader', 'private_post_reader', 'private_page_reader')" : '';
     if ($use_term_restrictions) {
         $term_restriction_query = "SELECT rs.obj_or_term_id AS term_id, rs.role_name, rs.max_scope FROM {$wpdb->role_scope_rs} AS rs " . "INNER JOIN {$wpdb->term_taxonomy} AS tt ON tt.taxonomy = rs.src_or_tx_name AND tt.taxonomy = 'category' AND tt.term_taxonomy_id = rs.obj_or_term_id " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('entity', 'both') AND rs.topic = 'term' {$role_clause}";
         $term_default_restriction_query = "SELECT rs.role_name FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('children', 'both') AND rs.topic = 'term' AND rs.max_scope = 'term' AND rs.src_or_tx_name = 'category' AND rs.obj_or_term_id = '0' {$role_clause}";
         $all_terms = array();
         $all_terms['category'] = $scoper->get_terms('category', false, COL_ID_RS);
         if ($results = scoper_get_results($term_restriction_query)) {
             foreach ($results as $row) {
                 if ('blog' == $row->max_scope) {
                     $unrestricted_roles['category'][$row->role_name][] = $row->term_id;
                 } else {
                     $restricted_roles['category'][$row->role_name][] = $row->term_id;
                 }
             }
         }
         // if there a role is default-restricted, mark all terms as restricted (may be unrestricted later)
         if ($results = scoper_get_col($term_default_restriction_query)) {
             foreach ($results as $role_name) {
                 if (isset($unrestricted_roles['category'][$role_name])) {
                     $default_restricted = array_diff($all_terms['category'], $unrestricted_roles['category'][$role_name]);
                 } else {
                     $default_restricted = $all_terms['category'];
                 }
                 if (isset($restricted_roles['category'][$role_name])) {
                     $restricted_roles['category'][$role_name] = array_unique(array_merge($restricted_roles['category'][$role_name], $default_restricted));
                 } else {
                     $restricted_roles['category'][$role_name] = $default_restricted;
                 }
             }
         }
         $restricted_terms['category'] = isset($restricted_roles['category']) ? agp_array_flatten($restricted_roles['category']) : array();
         if ($restricted_terms['category']) {
             $term_restriction_clause = "OR post_parent IN ( SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} " . "INNER JOIN {$wpdb->term_relationships} AS tr ON tr.object_id = {$wpdb->posts}.ID " . "WHERE tr.term_taxonomy_id IN ('" . implode("','", $restricted_terms['category']) . "') )";
         }
     }
     if ($attachment_id) {
         if (is_array($attachment_id)) {
             $id_clause = "AND ID IN ('" . implode("','", $attachment_id) . "')";
         } else {
             $id_clause = "AND ID = '{$attachment_id}'";
             $limit_clause = 'LIMIT 1';
         }
     } elseif ($guid) {
         $id_clause = "AND guid = '{$file_path}'";
     } else {
         $id_clause = '';
     }
     if (defined('SCOPER_NO_THUMBNAIL_FILTER')) {
         if ($thumbnail_ids = scoper_get_col("SELECT DISTINCT meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_thumbnail_id'")) {
             $id_clause .= " AND ID NOT IN ('" . implode("','", $thumbnail_ids) . "')";
         }
     }
     if ($attachments) {
         // to reduce pool of objects, we only care about those that have an attachment
         $attachment_query = "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.ID IN ( SELECT post_parent FROM {$wpdb->posts} WHERE post_type = 'attachment' {$id_clause} ) ";
     }
     if ($use_object_restrictions) {
         $object_restriction_query = "SELECT rs.obj_or_term_id AS obj_id, rs.role_name, rs.max_scope FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('entity', 'both') AND rs.topic = 'object' AND rs.src_or_tx_name = 'post' {$role_clause} AND rs.obj_or_term_id IN ( {$attachment_query} )";
         $object_default_restriction_query = "SELECT rs.role_name FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.require_for IN ('children', 'both') AND rs.topic = 'object' AND rs.max_scope = 'object' AND rs.src_or_tx_name = 'post' AND rs.obj_or_term_id = '0' {$role_clause}";
         $all_objects = array();
         $all_objects['post'] = scoper_get_col($attachment_query);
         $restricted_roles = array();
         $unrestricted_roles = array();
         if ($results = scoper_get_results($object_restriction_query)) {
             foreach ($results as $row) {
                 if ('blog' == $row->max_scope) {
                     $unrestricted_roles['post'][$row->role_name][] = $row->obj_id;
                 } else {
                     $restricted_roles['post'][$row->role_name][] = $row->obj_id;
                 }
             }
         }
         // if there a role is default-restricted, mark all terms as restricted (may be unrestricted later)
         if ($results = scoper_get_col($object_default_restriction_query)) {
             foreach ($results as $role_name) {
                 if (isset($unrestricted_roles['category'][$role_name])) {
                     $default_restricted = array_diff($all_terms['post'], $unrestricted_roles['post'][$role_name]);
                 } else {
                     $default_restricted = $all_objects['post'];
                 }
                 if (isset($restricted_roles['post'][$role_name])) {
                     $restricted_roles['post'][$role_name] = array_unique(array_merge($restricted_roles['post'][$role_name], $default_restricted));
                 } else {
                     $restricted_roles['post'][$role_name] = $default_restricted;
                 }
             }
         }
         if (!empty($restricted_roles)) {
             $restricted_objects['post'] = array_unique(agp_array_flatten($restricted_roles['post']));
             if ($restricted_objects['post']) {
                 $object_restriction_clause = "OR post_parent IN ( SELECT ID FROM {$wpdb->posts} WHERE ID IN ('" . implode("','", $restricted_objects['post']) . "') )";
             }
         }
     }
     if ($use_private_status) {
         $status_query = "AND post_parent IN ( SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.post_status = 'private' )";
     }
     if ($attachments) {
         $attachment_type_clause = "post_type = 'attachment' AND";
         $unattached_clause = defined('SCOPER_BLOCK_UNATTACHED_UPLOADS') ? " OR post_parent < 1" : '';
     }
     $single_col = false;
     if (COLS_ALL_RS === $cols) {
         $query_cols = '*';
     } elseif (COL_ID_RS == $cols) {
         $query_cols = 'ID';
         $single_col = true;
     } elseif (COLS_ID_DISPLAYNAME_RS == $cols) {
         if ($attachment) {
             $query_cols = 'ID, post_title, guid';
         } else {
             $query_cols = 'ID, post_title';
         }
     } else {
         if ($attachments) {
             $query_cols = 'ID, guid';
         } else {
             $query_cols = 'ID';
             $single_col = true;
         }
     }
     $query = "SELECT {$query_cols} FROM {$wpdb->posts} WHERE {$attachment_type_clause} ( 1=1 {$status_query} {$term_restriction_clause} {$object_restriction_clause} {$unattached_clause} ) {$id_clause} ORDER BY ID DESC {$limit_clause}";
     if ($attachment_id && !is_array($attachment_id)) {
         if ($single_col) {
             $results = scoper_get_var($query);
         } else {
             $results = scoper_get_row($query);
         }
     } else {
         if ($single_col) {
             $results = scoper_get_col($query);
         } else {
             $results = scoper_get_results($query);
         }
     }
     return $results;
 }
function scoper_filter_terms_for_status($taxonomy, $selected_terms, &$user_terms, $args = array())
{
    if (defined('DISABLE_QUERYFILTERS_RS') || defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return $selected_terms;
    }
    global $scoper;
    $defaults = array('object_id' => 0, 'object_type' => '', 'status' => '');
    $args = array_merge($defaults, $args);
    extract($args);
    if (!($tx = $scoper->taxonomies->get($taxonomy))) {
        return $selected_terms;
    }
    if (!($src = $scoper->data_sources->get($tx->object_source))) {
        return $selected_terms;
    }
    if (!isset($src->statuses) || count($src->statuses) < 2) {
        return $selected_terms;
    }
    if (!$object_id) {
        $object_id = scoper_get_object_id($src->name);
    }
    if (!$status) {
        // determine current post status
        if (defined('XMLRPC_REQUEST') && !empty($GLOBALS['scoper_xmlrpc_post_status'])) {
            $status = $GLOBALS['scoper_xmlrpc_post_status'];
        } else {
            if (!($status = $scoper->data_sources->get_from_http_post('status', $src))) {
                if ($object_id) {
                    $status = $scoper->data_sources->get_from_db('status', $src, $object_id);
                }
            }
        }
    }
    if (!$object_type) {
        if (!($object_type = cr_find_object_type($src->name, $object_id))) {
            if (defined('XMLRPC_REQUEST')) {
                $object_type = 'post';
            } else {
                return $selected_terms;
            }
        }
    }
    if ('auto-draft' == $status) {
        $status = 'draft';
    }
    // make sure _others caps are required only for objects current user doesn't own
    $base_caps_only = true;
    if ($object_id && !empty($src->cols->owner)) {
        $col_owner = $src->cols->owner;
        if ($object = $scoper->data_sources->get_object($src->name, $object_id)) {
            if (!empty($object->{$col_owner}) && $object->{$col_owner} != $GLOBALS['current_user']->ID) {
                $base_caps_only = false;
            }
        }
    }
    if (!($reqd_caps = cr_get_reqd_caps($src->name, OP_EDIT_RS, $object_type, $status, $base_caps_only))) {
        return $selected_terms;
    }
    $qualifying_roles = $scoper->role_defs->qualify_roles($reqd_caps);
    if ($qualifying_term_assigner_roles = $scoper->role_defs->qualify_roles(array("assign_{$taxonomy}"))) {
        $qualifying_roles = array_merge($qualifying_roles, $qualifying_term_assigner_roles);
    }
    $user_terms = $scoper->qualify_terms_daterange($reqd_caps, $taxonomy, $qualifying_roles);
    foreach (array_keys($user_terms) as $date_key) {
        $date_clause = '';
        if ($date_key && is_serialized($date_key)) {
            // Check stored post date against any role date limits associated whith this set of terms (if not stored, check current date)
            $content_date_limits = unserialize($date_key);
            $post_date_gmt = $object_id ? $scoper->data_sources->get_from_db('date', $src, $object_id) : 0;
            if (!$post_date_gmt) {
                $post_date_gmt = agp_time_gmt();
            }
            if ($post_date_gmt < $content_date_limits->content_min_date_gmt || $post_date_gmt > $content_date_limits->content_max_date_gmt) {
                unset($user_terms[$date_key]);
            }
        }
    }
    $user_terms = agp_array_flatten($user_terms);
    $selected_terms = array_intersect($selected_terms, $user_terms);
    return $selected_terms;
}
 function group_members_checklist($group_id, $user_class = 'member', $all_users = '')
 {
     global $scoper;
     if (!$all_users) {
         $all_users = $scoper->users_who_can('', COLS_ID_NAME_RS);
     }
     if ($group_id) {
         $group = ScoperAdminLib::get_group($group_id);
     }
     if ('member' == $user_class) {
         $current_ids = $group_id ? array_flip(ScoperAdminLib::get_group_members($group_id, COL_ID_RS)) : array();
         if (!empty($group) && in_array($group->meta_id, array('rv_pending_rev_notice_ed_nr_', 'rv_scheduled_rev_notice_ed_nr_'))) {
             $args = array('any_object' => true);
             $eligible_ids = array();
             foreach (get_post_types(array('public' => true), 'object') as $_type => $_type_obj) {
                 $args['object_type'] = $_type;
                 $type_eligible_ids = $scoper->users_who_can(array($_type_obj->cap->edit_published_posts, $_type_obj->cap->edit_others_posts), COL_ID_RS, 'post', 0, $args);
                 $eligible_ids = array_merge($eligible_ids, $type_eligible_ids);
             }
             $eligible_ids = array_unique($eligible_ids);
         } else {
             // force_all_users arg is a temporary measure to ensure that any user can be viewed / added to a sitewide MU group regardless of what blog backend it's edited through
             $_args = IS_MU_RS && scoper_get_option('mu_sitewide_groups', true) ? array('force_all_users' => true) : array();
             $eligible_ids = $scoper->users_who_can('', COL_ID_RS, '', '', $_args);
         }
         $admin_ids = array();
     } else {
         $group_role_defs = 'moderator' == $user_class ? array('rs_group_moderator') : array('rs_group_manager');
         if ($group_id) {
             require_once dirname(__FILE__) . '/role_assignment_lib_rs.php';
             $current_roles = ScoperRoleAssignments::organize_assigned_roles(OBJECT_SCOPE_RS, 'group', $group_id, $group_role_defs, ROLE_BASIS_USER);
             $current_roles = agp_array_flatten($current_roles, false);
             $current_ids = isset($current_roles['assigned']) ? $current_roles['assigned'] : array();
         } else {
             $current_ids = array();
         }
         $cap_name = defined('SCOPER_USER_ADMIN_CAP') ? constant('SCOPER_USER_ADMIN_CAP') : 'edit_users';
         $admin_ids = $scoper->users_who_can($cap_name, COL_ID_RS);
         // optionally, limit available group managers according to role_admin_blogwide_editor_only option
         if ('manager' == $user_class) {
             $require_blogwide_editor = false;
             if (!empty($group)) {
                 if (!strpos($group->meta_id, '_nr_')) {
                     // don't limit manager selection for groups that don't have role assignments
                     $require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only');
                 }
             }
             if ('admin' == $require_blogwide_editor) {
                 $eligible_ids = $admin_ids;
             } elseif ('admin_content' == $require_blogwide_editor) {
                 $cap_name = defined('SCOPER_CONTENT_ADMIN_CAP') ? constant('SCOPER_CONTENT_ADMIN_CAP') : 'activate_plugins';
                 $eligible_ids = array_unique(array_merge($admin_ids, $scoper->users_who_can($cap_name, COL_ID_RS)));
             } elseif ($require_blogwide_editor) {
                 $post_editors = $scoper->users_who_can('edit_others_posts', COL_ID_RS);
                 $page_editors = $scoper->users_who_can('edit_others_pages', COL_ID_RS);
                 $eligible_ids = array_unique(array_merge($post_editors, $page_editors, $admin_ids));
             } else {
                 $eligible_ids = '';
             }
         } else {
             $eligible_ids = '';
         }
     }
     // endif user class is not "member"
     $css_id = $user_class;
     $args = array('eligible_ids' => $eligible_ids, 'via_other_scope_ids' => $admin_ids, 'suppress_extra_prefix' => true);
     require_once dirname(__FILE__) . '/agents_checklist_rs.php';
     ScoperAgentsChecklist::agents_checklist(ROLE_BASIS_USER, $all_users, $css_id, $current_ids, $args);
 }
 function qualify_terms_daterange($reqd_caps, $taxonomy = 'category', $qualifying_roles = '', $args = array())
 {
     $defaults = array('user' => '', 'return_id_type' => COL_ID_RS, 'use_blog_roles' => true, 'ignore_restrictions' => false);
     if (isset($args['qualifying_roles'])) {
         unset($args['qualifying_roles']);
     }
     if (isset($args['reqd_caps'])) {
         unset($args['reqd_caps']);
     }
     $args = array_merge($defaults, (array) $args);
     extract($args);
     if (!$qualifying_roles) {
         // calling function might save a little work or limit to a subset of qualifying roles
         $qualifying_roles = $this->role_defs->qualify_roles($reqd_caps);
     }
     if (!$this->taxonomies->is_member($taxonomy)) {
         return array('' => array());
     }
     if (!is_object($user)) {
         $user = $GLOBALS['current_rs_user'];
     }
     // If the taxonomy does not require objects to have at least one term, there are no strict terms.
     if (!$this->taxonomies->member_property($taxonomy, 'requires_term')) {
         $ignore_restrictions = true;
     }
     if (!is_array($qualifying_roles)) {
         $qualifying_roles = array($qualifying_roles => 1);
     }
     // no need to serialize and md5 the whole user object
     if (!empty($user)) {
         $args['user'] = $user->ID;
     }
     // try to pull previous result out of memcache
     ksort($qualifying_roles);
     $rolereq_key = md5(serialize($reqd_caps) . serialize(array_keys($qualifying_roles)) . serialize($args));
     if (isset($user->qualified_terms[$taxonomy][$rolereq_key])) {
         return $user->qualified_terms[$taxonomy][$rolereq_key];
     }
     if (!$qualifying_roles) {
         return array('' => array());
     }
     $all_terms = $this->get_terms($taxonomy, UNFILTERED_RS, COL_ID_RS);
     // returns term_id, even for WP > 2.3
     if (!isset($user->term_roles[$taxonomy])) {
         $user->get_term_roles_daterange($taxonomy);
     }
     // returns term_id for categories
     $good_terms = array('' => array());
     if ($user->term_roles[$taxonomy]) {
         foreach (array_keys($user->term_roles[$taxonomy]) as $date_key) {
             //narrow down to roles which satisfy this call AND are owned by current user
             if ($good_terms[$date_key] = array_intersect_key($user->term_roles[$taxonomy][$date_key], $qualifying_roles)) {
                 // flatten from term_roles_terms[role_handle] = array of term_ids
                 // to term_roles_terms = array of term_ids
                 $good_terms[$date_key] = agp_array_flatten($good_terms[$date_key]);
             }
         }
     }
     if ($use_blog_roles) {
         foreach (array_keys($user->blog_roles) as $date_key) {
             $user_blog_roles = array_intersect_key($user->blog_roles[$date_key], $qualifying_roles);
             // Also include user's WP blogrole(s) which correspond to the qualifying RS role(s)
             if ($wp_qualifying_roles = $this->role_defs->qualify_roles($reqd_caps, 'wp')) {
                 if ($user_blog_roles_wp = array_intersect_key($user->blog_roles[$date_key], $wp_qualifying_roles)) {
                     // Credit user's qualifying WP blogrole via equivalent RS role(s)
                     // so we can also enforce "term restrictions", which are based on RS roles
                     $user_blog_roles_via_wp = $this->role_defs->get_contained_roles(array_keys($user_blog_roles_wp), false, 'rs');
                     $user_blog_roles_via_wp = array_intersect_key($user_blog_roles_via_wp, $qualifying_roles);
                     $user_blog_roles = array_merge($user_blog_roles, $user_blog_roles_via_wp);
                 }
             }
             if ($user_blog_roles) {
                 if (empty($ignore_restrictions)) {
                     // array of term_ids that require the specified role to be assigned via taxonomy or object role (user blog caps ignored)
                     $strict_terms = $this->get_restrictions(TERM_SCOPE_RS, $taxonomy);
                 } else {
                     $strict_terms = array();
                 }
                 foreach (array_keys($user_blog_roles) as $role_handle) {
                     if (isset($strict_terms['restrictions'][$role_handle]) && is_array($strict_terms['restrictions'][$role_handle])) {
                         $terms_via_this_role = array_diff($all_terms, array_keys($strict_terms['restrictions'][$role_handle]));
                     } elseif (isset($strict_terms['unrestrictions'][$role_handle]) && is_array($strict_terms['unrestrictions'][$role_handle])) {
                         $terms_via_this_role = array_intersect($all_terms, array_keys($strict_terms['unrestrictions'][$role_handle]));
                     } else {
                         $terms_via_this_role = $all_terms;
                     }
                     if ($good_terms[$date_key]) {
                         $good_terms[$date_key] = array_merge($good_terms[$date_key], $terms_via_this_role);
                     } else {
                         $good_terms[$date_key] = $terms_via_this_role;
                     }
                 }
             }
         }
     }
     foreach (array_keys($good_terms) as $date_key) {
         if ($good_terms[$date_key] = array_intersect($good_terms[$date_key], $all_terms)) {
             // prevent orphaned category roles from skewing access
             $good_terms[$date_key] = array_unique($good_terms[$date_key]);
         }
         // if COL_TAXONOMY_ID_RS, return a term_taxonomy_id instead of term_id
         if ($good_terms[$date_key] && COL_TAXONOMY_ID_RS == $return_id_type && taxonomy_exists($taxonomy)) {
             $all_terms_cols = $this->get_terms($taxonomy, UNFILTERED_RS);
             $good_tt_ids = array();
             foreach ($good_terms[$date_key] as $term_id) {
                 foreach (array_keys($all_terms_cols) as $termkey) {
                     if ($all_terms_cols[$termkey]->term_id == $term_id) {
                         $good_tt_ids[] = $all_terms_cols[$termkey]->term_taxonomy_id;
                         break;
                     }
                 }
             }
             $good_terms[$date_key] = $good_tt_ids;
         }
     }
     $user->qualified_terms[$taxonomy][$rolereq_key] = $good_terms;
     return $good_terms;
 }
 function update_user_groups_multi_status($user_id, $stored_groups, $editable_group_ids)
 {
     global $current_rs_user;
     $posted_groups = array();
     $is_administrator = is_user_administrator_rs();
     $can_manage = $is_administrator || current_user_can('manage_groups');
     $can_moderate = $can_manage || current_user_can('recommend_group_membership');
     if (!$can_moderate && !current_user_can('request_group_membership')) {
         return;
     }
     if ($can_manage) {
         $posted_groups['active'] = explode(',', trim($_POST['current_agents_rs_csv'], ''));
     } else {
         $stored_groups = array_diff_key($stored_groups, array('active' => true));
     }
     if ($can_moderate) {
         $posted_groups['recommended'] = !empty($_POST['recommended_agents_rs_csv']) ? explode(',', trim($_POST['recommended_agents_rs_csv'], '')) : array();
         $stored_groups['recommended'] = array_fill_keys($current_rs_user->get_groups_for_user($current_rs_user->ID, array('status' => 'recommended')), true);
         $editable_group_ids['recommended'] = ScoperAdminLib::get_all_groups(FILTERED_RS, COL_ID_RS, array('reqd_caps' => 'recommend_group_membership'));
         if (isset($editable_group_ids['active'])) {
             $editable_group_ids['recommended'] = array_unique($editable_group_ids['recommended'] + $editable_group_ids['active']);
         }
     }
     $stored_groups['requested'] = array_fill_keys($current_rs_user->get_groups_for_user($current_rs_user->ID, array('status' => 'requested')), true);
     $editable_group_ids['requested'] = ScoperAdminLib::get_all_groups(FILTERED_RS, COL_ID_RS, array('reqd_caps' => 'request_group_membership'));
     if (isset($editable_group_ids['recommended'])) {
         $editable_group_ids['requested'] = array_unique($editable_group_ids['requested'] + $editable_group_ids['recommended']);
     }
     $posted_groups['requested'] = !empty($_POST['requested_agents_rs_csv']) ? explode(',', trim($_POST['requested_agents_rs_csv'], '')) : array();
     $all_posted_groups = agp_array_flatten($posted_groups);
     $all_stored_groups = array();
     foreach (array_keys($stored_groups) as $status) {
         $all_stored_groups = $all_stored_groups + $stored_groups[$status];
     }
     foreach ($stored_groups as $status => $stored) {
         if (!$editable_group_ids[$status]) {
             continue;
         }
         // remove group memberships which were not posted for any status, if logged user can edit the group
         foreach (array_keys($stored) as $group_id) {
             if (!in_array($group_id, $all_posted_groups)) {
                 if (in_array($group_id, $editable_group_ids[$status])) {
                     ScoperAdminLib::remove_group_user($group_id, $user_id);
                 }
             }
         }
     }
     foreach ($posted_groups as $status => $posted) {
         if (!$editable_group_ids[$status]) {
             continue;
         }
         // insert or update group memberships as specified, if logged user can edit the group
         foreach ($posted as $group_id) {
             if (in_array($group_id, $editable_group_ids[$status])) {
                 if (!in_array($group_id, $all_stored_groups)) {
                     ScoperAdminLib::add_group_user($group_id, $user_id, $status);
                 } elseif (!in_array($group_id, $stored_groups[$status])) {
                     ScoperAdminLib::update_group_user($group_id, $user_id, $status);
                 }
             }
         }
     }
 }
 function user_can_for_any_term($reqd_caps, $user = '')
 {
     if (!is_object($user)) {
         $user = $GLOBALS['current_rs_user'];
     }
     // Instead of just intersecting the missing reqd_caps with termcaps from all term_roles,
     // require each subset of caps with matching src_name, object type and op_type to
     // all be satisfied by the same role (any assigned term role).  This simulates flt_objects_where behavior (which does so to support role restrictions.
     $grant_caps = array();
     $caps_by_otype = $this->scoper->cap_defs->organize_caps_by_otype($reqd_caps);
     // temp workaround
     if ('manage_categories' == current($reqd_caps) && isset($caps_by_otype['post']['link'])) {
         $caps_by_otype['link']['link_category'] = $caps_by_otype['post']['link'];
         unset($caps_by_otype['post']['link']);
     }
     foreach ($caps_by_otype as $src_name => $otypes) {
         $object_types = $this->scoper->data_sources->member_property($src_name, 'object_types');
         // deal with upload_files and other capabilities which have no specific object type
         if (!array_diff_key($otypes, array('' => true))) {
             foreach (array_keys($object_types) as $_object_type) {
                 $otypes[$_object_type] = $otypes[''];
             }
             unset($otypes['']);
         }
         $uses_taxonomies = scoper_get_taxonomy_usage($src_name, array_keys($otypes));
         // this ensures we don't credit term roles on custom taxonomies which have been disabled
         if (!($uses_taxonomies = array_intersect($uses_taxonomies, $this->scoper->taxonomies->get_all_keys()))) {
             continue;
         }
         foreach ($otypes as $this_otype_caps) {
             // keyed by object_type
             $caps_by_op = $this->scoper->cap_defs->organize_caps_by_op((array) $this_otype_caps);
             foreach ($caps_by_op as $this_op_caps) {
                 // keyed by op_type
                 $roles = $this->scoper->role_defs->qualify_roles($this_op_caps);
                 foreach ($uses_taxonomies as $taxonomy) {
                     if (!isset($user->term_roles[$taxonomy])) {
                         $user->term_roles[$taxonomy] = $user->get_term_roles_daterange($taxonomy);
                     }
                     // call daterange function populate term_roles property - possible perf enhancement for subsequent code even though we don't conider content_date-limited roles here
                     if (array_intersect_key($roles, agp_array_flatten($user->term_roles[$taxonomy], false))) {
                         // okay to include all content date ranges because can_for_any_term checks are only preliminary measures to keep the admin UI open
                         $grant_caps = array_merge($grant_caps, $this_op_caps);
                         break;
                     }
                 }
             }
         }
     }
     if ($grant_caps) {
         return array_fill_keys(array_unique($grant_caps), true);
     } else {
         return array();
     }
 }