/** * Edits fields for an existing key, given the key's key_id * * @version 1.0 * @since 1.0 * * @param array $data | one or more arrays, each descrribing a key to create * => VAL @param int $key_id | key_id for the key to edit * => VAL @param string $tree | tree name for key (max 32 chars) * => VAL @param string $branch | branch name for key (max 32 chars) * => VAL @param string $name | name for key (max 32 chars) * => VAL @param string $descr | admin description for key (max 255 chars) * * @return bool | False on failure. True on success. */ public function editKey($data) { global $fox; $db = new FOX_db(); // Get the column values for the current key // ========================================= // Trap missing $key_id if (!$data["key_id"]) { return false; } $columns = array("mode" => "exclude", "col" => array("key_id")); $ctrl = array("format" => "row"); try { $old = $db->runSelectQueryCol(self::$struct, "key_id", "=", $data["key_id"], $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("col" => "key_id", "op" => "=", "val" => $data["key_id"], "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If the key's $tree, $branch, or $name fields are being modified, check that a // key with the new combination does not already exist in the database // =================================================================================== $args = array(); // Tree // ========== if ($data["tree"] && $old["tree"] != $data["tree"]) { $args[] = array("col" => "tree", "op" => "=", "val" => $data["tree"]); $dupe_check_required = true; } else { $args[] = array("col" => "tree", "op" => "=", "val" => $old["tree"]); } // Branch // ========== if ($data["branch"] && $old["branch"] != $data["branch"]) { $args[] = array("col" => "branch", "op" => "=", "val" => $data["branch"]); $dupe_check_required = true; } else { $args[] = array("col" => "branch", "op" => "=", "val" => $old["branch"]); } // Name // ========== if ($data["name"] && $old["name"] != $data["name"]) { $args[] = array("col" => "name", "op" => "=", "val" => $data["name"]); $dupe_check_required = true; } else { $args[] = array("col" => "name", "op" => "=", "val" => $old["name"]); } if ($dupe_check_required) { $ctrl = array("count" => true, "format" => "var"); try { $key_exists = $db->runSelectQuery(self::$struct, $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // If possible, update the key in the database // ========================================================== if ($key_exists) { // Changes to the "Tree", "Branch" or "Name" fields would create a // collision with a key that already exists in the database. throw new FOX_exception(array('numeric' => 3, 'text' => "FOX_uKeyType::editKey - Attempted to rename a key to a value that would create a collission with an existing key.", 'data' => array("tree" => $data['tree'], "branch" => $data['branch'], "key" => $data['name']), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => null)); } else { // Add the key to the db and persistent cache $args = array(array("col" => "key_id", "op" => "=", "val" => $data["key_id"])); $columns = array("mode" => "exclude", "col" => array("key_id")); try { $result = $db->runUpdateQuery(self::$struct, $data, $args, $columns); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "DB update exception", 'data' => array("data" => $data, "args" => $args, "columns" => $columns), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($result) { // Update the class cache from the persistent cache try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Flush the old class cache entry unset($this->cache["keys"][$old["tree"]][$old["branch"]][$old["name"]]); // Set the new class cache entry $this->cache["keys"][$data["tree"]][$data["branch"]][$data["name"]] = $data["key_id"]; // Write the updated class cache array to the persistent cache try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return $cache_ok; } else { return false; } } }
/** * Returns all type_ids owned by a module * * @version 1.0 * @since 1.0 * @param int $module_id| Single module_id as int. * @return array | Exception on failure. False on nonexistent. Array of type_ids on success. */ public function getTypes($module_id) { $db = new FOX_db(); $result = array(); // If the module_id doesn't exist in the class cache array, fetch it from the persistent cache if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) { try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // If the module_id doesn't exist in the persistent cache, load it from the db if (!FOX_sUtil::keyExists($module_id, $this->cache["module_id_types"])) { $columns = array("mode" => "include", "col" => array("type_id")); $ctrl = array("format" => "col"); try { $db_result = $db->runSelectQueryCol($this->_struct(), "module_id", "=", $module_id, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading from database", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Update the cache // ============================== if ($db_result) { try { $cache_image = self::readCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Cache read error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the cache image foreach ($db_result as $type_id) { $result[] = $type_id; $cache_image["module_id_types"][$module_id][$type_id] = true; } unset($type_id); try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Overwrite the class cache $this->cache = $cache_image; } else { // The module_id doesn't exist return false; } } } // Build the result array $type_ids = $this->cache["module_id_types"][$module_id]; $result = array_keys($type_ids); return $result; }
/** * Edits an existing level * * @version 1.0 * @since 1.0 * * @param array $data | * => VAL @param int $level_id | Unique id for this access level. * => VAL @param string $level_slug | Slug name for this level. Must be unique to all other slugs. * => VAL @param string $level_name | Name of the level. Max 64 characters. * => VAL @param string $level_desc | Description of the level. Max 255 characters. * => VAL @param int $rank | Rank of this level within the object type. 1-255 where 1 is the highest. * => VAL @param int $key_id | Key id required to access to this level * * @return int | Exception on failure. False on no change. True on success. */ public function editLevel($data) { $db = new FOX_db(); if (!$data["level_id"]) { throw new FOX_exception(array('numeric' => 1, 'text' => "Missing level_id in data array", 'data' => $data, 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } // Nulling these columns prevents a user accidentally changing the module_id and // type_id values by passing in array keys for them when they're not supposed to. unset($data["module_id"]); unset($data["type_id"]); // We have to load the original row from the database before we modify it. This is so we know // the original $level_slug value so we can delete it from the cache if the user changes it, and // so we can build an efficient query that only updates fields that have been changed. $ctrl = array("format" => "row_array"); try { $row_data = $db->runSelectQueryCol($this->_struct(), "level_id", "=", $data["level_id"], $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "Error reading from database", 'data' => array('level_id' => $data["level_id"], 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Compare the existing column values to the new column values in the $data array, and add // any columns with updated values to the $update_data array. $update_data = array(); foreach ($data as $col => $val) { if ($row_data[$col] != $val) { $update_data[$col] = $val; } } unset($col, $val); // If rank is being updated, check that the new rank doesn't already exist // ========================================================================= if ($update_data["rank"]) { $args = array(array("col" => "module_id", "op" => "=", "val" => $row_data["module_id"]), array("col" => "type_id", "op" => "=", "val" => $row_data["type_id"]), array("col" => "rank", "op" => "=", "val" => $data["rank"])); $ctrl = array("format" => "var", "count" => true); try { $already_exists = $db->runSelectQuery($this->_struct(), $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "Error reading from database", 'data' => array('args' => $args, 'ctrl' => $ctrl), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } if ($already_exists) { throw new FOX_exception(array('numeric' => 4, 'text' => "Rank you are trying to change target item to already exists", 'data' => array('data' => $data, 'faulting_rank' => $update_data["rank"]), 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => null)); } } // If there are no values that need to be updated, return false to indicate no db rows were changed. // Otherwise, run the query. Rules set when the database table was created will prevent duplicate // $level_slugs and duplicate $rank values within a $level_id, and other data integrity problems. if (count($update_data) == 0) { return false; } // Lock the cache // ========================== try { $cache_image = self::lockCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "Error locking cache", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Run the update // ========================== try { $rows_changed = $db->runUpdateQueryCol($this->_struct(), $update_data, "level_id", "=", $data["level_id"], $columns = null); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "Error writing to database", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Rebuild the cache image // ========================== // If the level's $slug value was changed, delete the old entry and create a // new one in the slug_to_id cache table if ($update_data["level_slug"] && $update_data["level_slug"] != $row_data["level_slug"]) { unset($cache_image["slug_to_level_id"][$row_data["module_id"]][$row_data["type_id"]][$row_data["level_slug"]]); $cache_image["slug_to_level_id"][$row_data["module_id"]][$row_data["type_id"]][$data["level_slug"]] = $row_data["level_id"]; } // If the level's $rank value was changed, delete the old entry and create a // new entry in the type_levels cache table if ($update_data["rank"] && $update_data["rank"] != $row_data["rank"]) { unset($cache_image["type_levels"][$row_data["type_id"]][$row_data["rank"]]); $cache_image["type_levels"][$row_data["type_id"]][$data["rank"]] = true; } // Update any changed keys in the main cache table foreach ($update_data as $col => $val) { $cache_image["keys"][$data["level_id"]][$col] = $val; } unset($col, $val); // Update the persistent cache, releasing our lock // =========================================================== try { self::writeCache($cache_image); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "Cache write error", 'file' => __FILE__, 'class' => __CLASS__, 'function' => __FUNCTION__, 'line' => __LINE__, 'child' => $child)); } // Overwrite the class cache $this->cache = $cache_image; return (bool) $rows_changed; }
/** * Deletes a single group, given its group_id * * @version 1.0 * @since 1.0 * * @param int $group_id | id of the group * @return bool | False on failure. True on success. */ public function deleteGroup($group_id) { global $fox; $db = new FOX_db(); $columns = array("mode" => "include", "col" => array("is_default", "name")); $ctrl = array("format" => "row_array"); try { $group = $db->runSelectQueryCol(self::$struct, "group_id", "=", $group_id, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // If the group we're trying to delete is the default group, reject the action. There must *always* be a // default group on the system. If the admin wants to delete the default group, they have to make // another group the default group first. if ($group["is_default"] == true) { //echo "\nclass.user.group.types::deleteGroup() - attempted delete on default group\n"; return false; } // Trap trying to delete a nonexistent group if (!$group) { //echo "\nclass.user.group.types::deleteGroup() - attempted delete on nonexistent group: $group_id \n"; return false; } // Get the user_id of every user in the group we're deleting $columns = array("mode" => "include", "col" => "user_id"); $ctrl = array("format" => "col"); try { $user_ids = $db->runSelectQueryCol(FOX_uGroupMember::_struct(), "group_id", "=", $group_id, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // CASE 1: There are users that are members of the group // =============================================================================== if ($user_ids) { // Load all of the groups that each user is currently in, except // the group we're removing them from $args = array(array("col" => "user_id", "op" => "=", "val" => $user_ids), array("col" => "group_id", "op" => "!=", "val" => $group_id)); $ctrl = array("format" => "array_key_array_grouped", "key_col" => array("user_id", "group_id")); try { $in_groups = $db->runSelectQuery(FOX_uGroupMember::_struct(), $args, $columns = null, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "DB select exception", 'data' => array("args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $started_transaction = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 4, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($started_transaction) { $keys_ok = true; try { $gk = new FOX_uGroupKeyRing(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } foreach ($user_ids as $user) { // Get the combined keyring of all the user's other groups try { $keep_keys = $gk->getKeys($in_groups[$user]); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 5, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $in_groups[$user]), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Get the keyring of the group we're removing the user from try { $drop_keys = $gk->getKeys($group_id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 6, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Intersect the $keep_keys and $drop_keys arrays to get // a list of keys we need to revoke from the user if ($keep_keys && $drop_keys) { $revoke_keys = array_diff($drop_keys, $keep_keys); } else { $revoke_keys = $drop_keys; } // Revoke all the keys we previously calculated if ($revoke_keys) { $ks = new FOX_uKeyRing(); try { $revoke_ok = $ks->revokeKey($user, $revoke_keys); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 7, 'text' => "FOX_uKeyRing revokeKeys exception", 'data' => array("user" => $user, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if (!$revoke_ok) { $keys_ok = false; } } else { // Handle no keys to revoke $keys_ok = true; } } unset($user); // Because we are inside a transaction, we have to directly delete items from // the other class's db tables. If we deleted items using the other class's // functions, the other classes would remove them from their caches before we // could confirm all steps in the transaction were successful. // ============================================================================ // Drop the group-user pairs from the group members table $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $gm_ok = $db->runDeleteQuery(FOX_uGroupMember::_struct(), $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 8, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Drop the group-key pairs from the group keyring table $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 9, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Drop the group from the group types table $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $gt_ok = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 10, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($keys_ok && $gm_ok !== false && $gk_ok !== false && $gt_ok) { // Handle groups with no members and // groups with no keys returning (int)0 try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 11, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($commit_ok) { // Because we directly modified other class's db tables, we have to // flush the cache for the affected classes try { $fox->cache->flushNamespace("FOX_uGroupMember"); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 12, 'text' => "FOX_uGroupMember flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } try { $fox->cache->flushNamespace("FOX_uGroupKeyRing"); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 13, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Load, update, writeback try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 14, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } unset($this->cache["ids"][$group["name"]]); $cache_ok = self::saveCache(); return $cache_ok; } else { return false; } } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } else { // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ try { $started_transaction = $db->beginTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 15, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($started_transaction) { // Because we are inside a transaction, we have to directly delete items from // the other class's db tables. If we deleted items using the other class's // functions, the other classes would remove them from their caches before we // could confirm all steps in the transaction were successful. // ============================================================================ // Drop the group-key pairs from the group keyring table $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 16, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Drop the group from the group types table $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id)); try { $gt_ok = $db->runDeleteQuery(self::$struct, $args); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 17, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Update the cache if ($gk_ok !== false && $gt_ok) { // Handle groups with no keys // returning (int)0 try { $commit_ok = $db->commitTransaction(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 18, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } if ($commit_ok) { // Because we directly modified another class's db table, we // have to flush the cache for the affected class try { $fox->cache->flushNamespace("FOX_uGroupKeyRing"); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Load, update, writeback try { self::loadCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 19, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } unset($this->cache["ids"][$group["name"]]); try { $cache_ok = self::saveCache(); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 20, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } return $cache_ok; } else { return false; } } } else { // If we couldn't start a transaction, return false return false; } // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ } // It might be possible to do this using a sophisticated query // Remove all keys granted by the group, from every user on the site, unless another group grants // the key, and the user is a member of that other group // ======================================================== // DELETE kst // FROM user_keystore_table AS kst // INNER JOIN group_members_table AS gmt ON kst.user_id = gmt.user_id // user has to be a member of the deleted group // INNER JOIN group_keyring_table AS gkt ON gmt.group_id = gkt.group_id // key has to be granted by the deleted group // WHERE kst.key_id NOT IN (SELECT key_id // FROM group_keyring_table AS gkt2 // INNER JOIN group_members_table AS gmt2 ON gkt2.group_id = gmt2.group_id // WHERE gmt2.group_id != gmt.group_id // where the key does not belong to another group // AND gmt2.user_id = gmt.user_id ) // and the user is a member of that group // AND gkt.group_id = [this group] // AND gmt.group_id = [this group] // ...It also might be possible to do this using MySQL "foreign keys" }
/** * Deletes an existing user class. Users in this class will be moved to the class's "transfer_to" * class. If the "transfer_to" class was not set, users will be moved to the site's "default" class. * * @version 1.0 * @since 1.0 * * @param int $id | id of this class to delete * @return bool/int | False on failure. Numer of affected users on success. */ public function deleteClass($id) { // Fetch the db entry for this user class // ============================================================================================ $db = new FOX_db(); $columns = array("format" => "include", "col" => array("id", "is_default", "transfer_to")); $ctrl = array("format" => "row_array"); try { $result = $db->runSelectQueryCol(self::$struct, "id", "=", $id, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("col" => "id", "op" => "=", "val" => $id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // Trap user trying to delete the default class // ============================================================================================ if ($result["is_default"] == true) { echo "\nERROR: You cannot delete a class that is set as the default user class. To delete this "; echo "class, set another class as the default class, then come back and delete this one.\n"; die; } // If the old class has a "transfer_to" class, use it. If the old class doesn't list a // "transfer_to" class, find the class that has the "default" flag, and use that class instead. // ============================================================================================ if (!empty($result["transfer_to"])) { $dest_class = $result["transfer_to"]; } else { $columns = array("format" => "include", "col" => "id"); $ctrl = array("format" => "var"); try { $dest_class = $db->runSelectQueryCol(self::$struct, "is_default", "=", true, $columns, $ctrl); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("col" => "is_default", "op" => "=", "val" => true, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } } // Run the update query // ============================================================================================ $update = array("user_class_id" => $dest_class, "when_class_set" => gmdate("Y-m-d H:i:s"), "when_class_expires" => null); try { $result = $db->runUpdateQueryCol(FOX_user::_struct(), $update, "user_class_id", "=", $id); } catch (FOX_exception $child) { throw new FOX_exception(array('numeric' => 3, 'text' => "DB update exception", 'data' => array("data" => $update, "col" => "usewr_class_id", "op" => "=", "val" => $id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child)); } // TODO: Although this code will move the users to the new class and delete the old class, it will cause // huge problems if the classes have different limitations. For example, if the old class allowed video // uploads in albums, and the new class does not. Or if the old class allowed 10 instances of an album // type and the new one does not, etc. We need to come up with ways to resolve these problems. }