/**
  * Updates an existing Group
  *
  * @param int $groupID - Group identifier
  * @param string $name - Name of the group
  * @param string $description - Group description (optional)
  * @return boolean True on successful update
  **/
 function updateGroup($group_id, $name, $description = '')
 {
     global $wpdb;
     $description = strip_tags($description);
     if ($prev = scoper_get_row("SELECT * FROM {$wpdb->groups_rs} WHERE {$wpdb->groups_id_col}='{$group_id}';")) {
         if ($prev->{$wpdb->groups_name_col} != $name && !UserGroups_tp::isValidName($name)) {
             return false;
         }
         // don't allow updating of metagroup name / descript
         if (!empty($prev->meta_id)) {
             return false;
         }
     }
     do_action('update_group_rs', $group_id);
     $query = "UPDATE {$wpdb->groups_rs} SET {$wpdb->groups_name_col} = '{$name}', {$wpdb->groups_descript_col}='{$description}' WHERE {$wpdb->groups_id_col}='{$group_id}';";
     scoper_query($query);
     wpp_cache_flush_group('all_usergroups');
     wpp_cache_flush_group('group_members');
     wpp_cache_flush_group('usergroups_for_user');
     wpp_cache_flush_group('usergroups_for_groups');
     wpp_cache_flush_group('usergroups_for_ug');
     return true;
 }
function scoper_flush_cache_flag_once($cache_flag)
{
    static $flushed_wpcache_flags;
    if (!isset($flushed_wpcache_flags)) {
        $flushed_wpcache_flags = array();
    }
    if (!isset($flushed_wpcache_flags[$cache_flag])) {
        wpp_cache_flush_group($cache_flag);
        $flushed_wpcache_flags[$cache_flag] = true;
    }
}
function scoper_sync_wproles($user_ids = '', $role_name_arg = '', $blog_id_arg = '')
{
    global $wpdb, $wp_roles;
    if ($user_ids && !is_array($user_ids)) {
        $user_ids = array($user_ids);
    }
    if (empty($wp_roles->role_objects)) {
        return;
    }
    $wp_rolenames = array_keys($wp_roles->role_objects);
    $uro_table = $blog_id_arg ? $wpdb->base_prefix . $blog_id_arg . '_' . 'user2role2object_rs' : $wpdb->user2role2object_rs;
    $groups_table = $wpdb->groups_rs;
    $user2group_table = $wpdb->user2group_rs;
    // Delete any role entries for WP roles which were deleted or renamed while Role Scoper was deactivated
    // (users will be re-synched to new role name)
    $name_in = "'" . implode("', '", $wp_rolenames) . "'";
    $qry = "DELETE FROM {$uro_table} WHERE role_type = 'wp' AND scope = 'blog' AND role_name NOT IN ({$name_in})";
    scoper_query($qry);
    // also sync WP Role metagroups
    if (!empty($user_ids)) {
        foreach ($user_ids as $user_id) {
            wpp_cache_delete($user_id, 'group_membership_for_user');
        }
    }
    $metagroup_ids = array();
    $metagroup_names = array();
    $metagroup_descripts = array();
    foreach ($wp_rolenames as $role_name) {
        $metagroup_id = "wp_role_" . trim(substr($role_name, 0, 40));
        // if the name is too long and its truncated ID already taken, just exclude it from eligible metagroups
        if (in_array($metagroup_id, $metagroup_ids)) {
            continue;
        }
        $metagroup_ids[] = $metagroup_id;
        $metagroup_names["wp_role_{$role_name}"] = sprintf('[WP %s]', $role_name);
        $metagroup_descripts["wp_role_{$role_name}"] = sprintf('All users with the WordPress %s blog role', $role_name);
    }
    // add a metagroup for anonymous users
    $metagroup_ids[] = "wp_anon";
    $metagroup_names["wp_anon"] = '[Anonymous]';
    $metagroup_descripts["wp_anon"] = 'Anonymous users (not logged in)';
    // add a metagroup for pending revision e-mail notification recipients
    $metagroup_ids[] = "rv_pending_rev_notice_ed_nr_";
    $metagroup_names["rv_pending_rev_notice_ed_nr_"] = '[Pending Revision Monitors]';
    $metagroup_descripts["rv_pending_rev_notice_ed_nr_"] = 'Administrators / Publishers to notify (by default) of pending revisions';
    // add a metagroup for pending revision e-mail notification recipients
    $metagroup_ids[] = "rv_scheduled_rev_notice_ed_nr_";
    $metagroup_names["rv_scheduled_rev_notice_ed_nr_"] = '[Scheduled Revision Monitors]';
    $metagroup_descripts["rv_scheduled_rev_notice_ed_nr_"] = 'Administrators / Publishers to notify when any scheduled revision is published';
    $stored_metagroup_ids = array();
    $qry = "SELECT {$wpdb->groups_meta_id_col}, {$wpdb->groups_id_col}, {$wpdb->groups_name_col} FROM {$groups_table} WHERE NOT ISNULL({$wpdb->groups_meta_id_col}) AND ( {$wpdb->groups_meta_id_col} != '' )";
    // LIKE 'wp_%'";
    if ($results = scoper_get_results($qry)) {
        //rs_errlog("metagroup results: " . serialize($stored_metagroup_ids)');
        $delete_metagroup_ids = array();
        $update_metagroup_ids = array();
        foreach ($results as $row) {
            if (!in_array($row->{$wpdb->groups_meta_id_col}, $metagroup_ids)) {
                $delete_metagroup_ids[] = $row->{$wpdb->groups_id_col};
            } else {
                $stored_metagroup_ids[] = $row->{$wpdb->groups_meta_id_col};
                if ($row->{$wpdb->groups_name_col} != $metagroup_names[$row->{$wpdb->groups_meta_id_col}]) {
                    $update_metagroup_ids[] = $row->{$wpdb->groups_meta_id_col};
                }
            }
        }
        if ($delete_metagroup_ids) {
            $id_in = "'" . implode("', '", $delete_metagroup_ids) . "'";
            scoper_query("DELETE FROM {$groups_table} WHERE {$wpdb->groups_id_col} IN ({$id_in})");
        }
        if ($update_metagroup_ids) {
            foreach ($update_metagroup_ids as $metagroup_id) {
                if ($metagroup_id) {
                    scoper_query("UPDATE {$groups_table} SET {$wpdb->groups_name_col} = '{$metagroup_names[$metagroup_id]}', {$wpdb->groups_descript_col} = '{$metagroup_descripts[$metagroup_id]}' WHERE {$wpdb->groups_meta_id_col} = '{$metagroup_id}'");
                }
            }
        }
    }
    if ($insert_metagroup_ids = array_diff($metagroup_ids, $stored_metagroup_ids)) {
        //rs_errlog("inserting metagroup ids: " . serialize($insert_metagroup_ids)');
        foreach ($insert_metagroup_ids as $metagroup_id) {
            scoper_query("INSERT INTO {$groups_table} ( {$wpdb->groups_meta_id_col}, {$wpdb->groups_name_col}, {$wpdb->groups_descript_col} ) VALUES ( '{$metagroup_id}', '{$metagroup_names[$metagroup_id]}', '{$metagroup_descripts[$metagroup_id]}' )");
            //rs_errlog( "INSERT INTO $groups_table ( $wpdb->groups_meta_id_col, $wpdb->groups_name_col, $wpdb->groups_descript_col ) VALUES ( '$metagroup_id', '$metagroup_names[$metagroup_id]', '$metagroup_descripts[$metagroup_id]' )" );
        }
    }
    if (!empty($delete_metagroup_ids) || !empty($update_metagroup_ids)) {
        wpp_cache_flush();
        // role deletion / rename might affect other cached data or settings, so flush the whole cache
    } elseif (!empty($insert_group_ids)) {
        wpp_cache_flush_group('all_usergroups');
        wpp_cache_flush_group('usergroups_for_groups');
        wpp_cache_flush_group('usergroups_for_user');
        wpp_cache_flush_group('usergroups_for_ug');
    }
    // Now step through every WP usermeta record,
    // synchronizing the user's user2role2object_rs blog role entries with their WP role and custom caps
    // get each user's WP roles and caps
    $user_clause = $user_ids ? 'AND user_id IN (' . implode(', ', $user_ids) . ')' : '';
    $qry = "SELECT user_id, meta_value FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' {$user_clause}";
    if (!($usermeta = scoper_get_results($qry))) {
        return;
    }
    //rs_errlog("got " . count($usermeta) . " usermeta records");
    $wp_rolecaps = array();
    foreach ($wp_roles->role_objects as $role_name => $role) {
        $wp_rolecaps[$role_name] = $role->capabilities;
    }
    //rs_errlog(serialize($wp_rolecaps));
    $strip_vals = array('', 0, false);
    $stored_assignments = array('wp' => array(), 'wp_cap' => array());
    foreach (array_keys($stored_assignments) as $role_type) {
        $results = scoper_get_results("SELECT user_id, role_name, assignment_id FROM {$uro_table} WHERE role_type = '{$role_type}' AND user_id > 0 {$user_clause}");
        foreach ($results as $key => $row) {
            $stored_assignments[$role_type][$row->user_id][$row->assignment_id] = $row->role_name;
            unset($results[$key]);
        }
    }
    foreach (array_keys($usermeta) as $key) {
        $user_id = $usermeta[$key]->user_id;
        $user_caps = maybe_unserialize($usermeta[$key]->meta_value);
        if (empty($user_caps) || !is_array($user_caps)) {
            continue;
        }
        //rs_errlog("user caps: " . serialize($user_caps));
        $user_roles = array();
        // just in case, strip out any entries with false value
        $user_caps = array_diff($user_caps, $strip_vals);
        $user_roles = array('wp' => array(), 'wp_cap' => array());
        //Filter out caps that are not role names
        $user_roles['wp'] = array_intersect(array_keys($user_caps), $wp_rolenames);
        // Store any custom-assigned caps as single-cap roles
        // This will be invisible and only used to support the users query filter
        // With current implementation, the custom cap will only be honored when
        // users_who_can is called with a single capreq
        $user_roles['wp_cap'] = array_diff(array_keys($user_caps), $user_roles['wp']);
        // which roles are already stored in user2role2object_rs table?
        $stored_roles = array();
        $delete_roles = array();
        foreach (array_keys($user_roles) as $role_type) {
            //$results = scoper_get_results("SELECT role_name, assignment_id FROM $uro_table WHERE role_type = '$role_type' AND user_id = '$user_id'");
            //if ( $results ) {
            if (isset($stored_assignments[$role_type][$user_id])) {
                //rs_errlog("results: " . serialize($results));
                foreach ($stored_assignments[$role_type][$user_id] as $assignment_id => $role_name) {
                    // Log stored roles, and delete any roles which user no longer has (possibly because the WP role definition was deleted).
                    // Only Role Scoper's mirroring of WP blog roles is involved here unless Role Scoper was configured and used with a Role Type of "WP".
                    // This also covers any WP role changes made while Role Scoper was deactivated.
                    if (in_array($role_name, $user_roles[$role_type])) {
                        $stored_roles[$role_type][] = $role_name;
                    } else {
                        $delete_roles[] = $assignment_id;
                    }
                }
            } else {
                $stored_roles[$role_type] = array();
            }
        }
        if ($delete_roles) {
            $id_in = implode(', ', $delete_roles);
            scoper_query("DELETE FROM {$uro_table} WHERE assignment_id IN ({$id_in})");
        }
        //rs_errlog("user roles " . serialize($user_roles) ');
        //rs_errlog("stored roles " . serialize($stored_roles)');
        // add any missing roles
        foreach (array_keys($user_roles) as $role_type) {
            if (!empty($stored_roles[$role_type])) {
                $user_roles[$role_type] = array_diff($user_roles[$role_type], $stored_roles[$role_type]);
            }
            if (!empty($user_roles[$role_type])) {
                foreach ($user_roles[$role_type] as $role_name) {
                    //rs_errlog("INSERT INTO $uro_table (user_id, role_name, role_type, scope) VALUES ('$user_id', '$role_name', '$role_type', 'blog')");
                    scoper_query("INSERT INTO {$uro_table} (user_id, role_name, role_type, scope) VALUES ('{$user_id}', '{$role_name}', '{$role_type}', 'blog')");
                }
            }
        }
    }
    // end foreach WP usermeta
    // disable orphaned role deletion until we can recreate and eliminate improper deletion as reported in support forum (http://agapetry.net/forum/role-scoper/permissions-reset-randomly-for-a-section-of-pages/page-1/post-3513/)
    // Delete any role assignments for users which no longer exist
    //delete_roles_orphaned_from_user();
    // Delete any role assignments for WP groups which no longer exist
    //delete_roles_orphaned_from_group();
    // Delete any role assignments for posts/pages which no longer exist
    //delete_roles_orphaned_from_item( OBJECT_SCOPE_RS, 'post' );
    //delete_restrictions_orphaned_from_item( OBJECT_SCOPE_RS, 'post' );	// hold off on this until delete_roles_orphaned_from_item() call has a long, clear track record
    // Delete any role assignments for categories which no longer exist
    //delete_roles_orphaned_from_item( TERM_SCOPE_RS, 'category' );
    //delete_restrictions_orphaned_from_item( TERM_SCOPE_RS, 'category' );
    //rs_errlog("finished syncroles "');
}
 function add_user($user_id, $role_name = '', $blog_id = '')
 {
     // enroll user in default group(s)
     if ($default_groups = scoper_get_option('default_groups')) {
         foreach ($default_groups as $group_id) {
             ScoperAdminLib::add_group_user($group_id, $user_id);
         }
     }
     global $scoper_role_types;
     foreach ($scoper_role_types as $role_type) {
         wpp_cache_flush_group("{$role_type}_users_who_can");
         wpp_cache_flush_group("{$role_type}_groups_who_can");
     }
     ScoperAdminLib::sync_wproles($user_id, $role_name, $blog_id);
 }
function scoper_flush_restriction_cache($scope, $src_or_tx_name = '')
{
    global $scoper_role_types;
    if (OBJECT_SCOPE_RS == $scope) {
        if (!$src_or_tx_name) {
            global $scoper;
            if (!empty($scoper->data_sources)) {
                $src_or_tx_name = $scoper->data_sources->get_all_keys();
            }
        }
    } elseif (TERM_SCOPE_RS == $scope) {
        if (!$src_or_tx_name) {
            global $scoper;
            if (!empty($scoper->taxonomies)) {
                $src_or_tx_name = $scoper->taxonomies->get_all_keys();
            }
        }
    }
    if (!$src_or_tx_name) {
        update_option('scoper_need_cache_flush', true);
        // if taxonomies / data sources could not be determined, invalidate entire cache
        return;
    }
    $names = (array) $src_or_tx_name;
    foreach ($scoper_role_types as $role_type) {
        foreach ($names as $src_or_tx_name) {
            wpp_cache_flush_group("{$role_type}_{$scope}_restrictions_{$src_or_tx_name}");
        }
    }
    foreach ($scoper_role_types as $role_type) {
        wpp_cache_flush_group("{$role_type}_{$scope}_def_restrictions");
    }
}