sql_r = new db; $this->fixed_classes = array(e_UC_PUBLIC => UC_LAN_0, e_UC_GUEST => UC_LAN_1, e_UC_NOBODY => UC_LAN_2, e_UC_MEMBER => UC_LAN_3, e_UC_ADMIN => UC_LAN_5, e_UC_MAINADMIN => UC_LAN_6, e_UC_READONLY => UC_LAN_4 ); $this->text_class_link = array('public' => e_UC_PUBLIC, 'guest' => e_UC_GUEST, 'nobody' => e_UC_NOBODY, 'member' => e_UC_MEMBER, 'admin' => e_UC_ADMIN, 'main' => e_UC_MAINADMIN, 'readonly' => e_UC_READONLY); $this->readTree(TRUE); // Initialise the classes on entry } /* Ensure the tree of userclass data is stored in our object. Only read if its either not present, or the $force flag is set */ function readTree($force = FALSE) { if (isset($this->class_tree) && count($this->class_tree) && !$force) return $this->class_tree; global $e107; $this->class_tree = array(); $this->class_parents = array(); $array = new ArrayData; if ($temp = $e107->ecache->retrieve_sys(UC_CACHE_TAG)) { $this->class_tree = $array->ReadArray($temp); unset($temp); } else { $this->sql_r->db_Select("userclass_classes", '*', "ORDER BY userclass_parent", 'nowhere'); // The order statement should give a consistent return while ($row = $this->sql_r->db_Fetch(MYSQL_ASSOC)) { $this->class_tree[$row['userclass_id']] = $row; $this->class_tree[$row['userclass_id']]['class_children'] = array(); // Create the child array in case needed } // Add in any fixed classes that aren't already defined foreach ($this->fixed_classes as $c => $d) { if (!isset($this->class_tree[$c]) && ($c != e_UC_PUBLIC)) { // $this->class_tree[$c]['userclass_parent'] = (($c == e_UC_MEMBER) || ($c == e_UC_NOBODY)) ? e_UC_PUBLIC : e_UC_MEMBER; $this->class_tree[$c]['userclass_parent'] = (($c == e_UC_ADMIN) || ($c == e_UC_MAINADMIN)) ? e_UC_MEMBER : e_UC_PUBLIC ; $this->class_tree[$c]['userclass_id'] = $c; $this->class_tree[$c]['userclass_name'] = $d; $this->class_tree[$c]['userclass_description'] = 'Fixed class'; $this->class_tree[$c]['userclass_visibility'] = e_UC_PUBLIC; $this->class_tree[$c]['userclass_editclass'] = e_UC_MAINADMIN; $this->class_tree[$c]['userclass_accum'] = $c; $this->class_tree[$c]['userclass_type'] = UC_TYPE_STD; } } $userCache = $array->WriteArray($this->class_tree, FALSE); $e107->ecache->set_sys(UC_CACHE_TAG,$userCache); unset($userCache); } // Now build the tree foreach ($this->class_tree as $uc) { if ($uc['userclass_parent'] == e_UC_PUBLIC) { // Note parent (top level) classes $this->class_parents[$uc['userclass_id']] = $uc['userclass_id']; } else { if (!array_key_exists($uc['userclass_parent'],$this->class_tree)) { echo "Orphaned class record: ID=".$uc['userclass_id']." Name=".$uc['userclass_name']." Parent=".$uc['userclass_parent']."
"; } else { // Add to array $this->class_tree[$uc['userclass_parent']]['class_children'][] = $uc['userclass_id']; } } } } // Given the list of 'base' classes a user belongs to, returns a comma separated list including ancestors. Duplicates stripped function get_all_user_classes($start_list) { $is = array(); $start_array = explode(',', $start_list); foreach ($start_array as $sa) { // Merge in latest values - should eliminate duplicates as it goes if (isset($this->class_tree[$sa])) { $is = array_merge($is,explode(',',$this->class_tree[$sa]['userclass_accum'])); } } return implode(',',array_unique($is)); } // Returns a list of user classes which can be edited by the specified classlist (defaults to current user's classes) function get_editable_classes($class_list = USERCLASS_LIST) { $ret = array(); $blockers = array(e_UC_PUBLIC => 1, e_UC_READONLY => 1, e_UC_MEMBER => 1, e_UC_NOBODY => 1, e_UC_GUEST => 1); $possibles = array_flip(explode(',',$class_list)); // unset($possibles[e_UC_PUBLIC]); unset($possibles[e_UC_READONLY]); foreach ($this->class_tree as $uc => $uv) { if (!isset($blockers[$uc])) { $ec = $this->class_tree[$uc]['userclass_editclass']; // echo "Check class: {$uc} editclass {$ec} in array: ".(isset($possibles[$ec]) ? 'yes' : 'no').'
'; if (isset($possibles[$ec])) { $ret[] = $uc; } } } return implode(',',$ret); } // Given a comma separated list, returns the minimum number of class memberships required to achieve this (i.e. strips classes 'above' another in the tree) // Requires the class tree to have been initialised function normalise_classes($class_list) { $drop_classes = array(); $old_classes = explode(',',$class_list); foreach ($old_classes as $c) { // Look at our parents (which are in 'userclass_accum') - if any of them are contained in old_classes, we can drop them. $tc = array_flip(explode(',',$this->class_tree[$c]['userclass_accum'])); unset($tc[$c]); // Current class should be in $tc anyway foreach ($tc as $tc_c => $v) { if (in_array($tc_c,$old_classes)) { $drop_classes[] = $tc_c; } } } $new_classes = array_diff($old_classes,$drop_classes); return implode(',',$new_classes); } /* Generate a dropdown list of user classes from which to select - virtually as r_userclass() $optlist allows selection of the classes to be shown in the dropdown. All or none can be included, separated by comma. Valid options are: public guest nobody member readonly admin main - main admin classes - shows all classes matchclass - if 'classes' is set, this option will only show the classes that the user is a member of language - list of languages. blank - puts an empty option at the top of select dropdowns filter - only show those classes where member is in a class permitted to view them - i.e. as the new 'visible to' field - added for 0.8 force - show all classes (subject to the other options, including matchclass) - added for 0.8 $extra_js - can add JS handlers (e.g. 'onclick', 'onchange') if required [ $mode parameter of r_userclass() removed - $optlist is more flexible) ] */ function uc_dropdown($fieldname, $curval = 0, $optlist = "", $extra_js = '') { global $pref; $show_classes = $this->uc_required_class_list($optlist); $text = ''; foreach ($show_classes as $k => $v) { if ($k == e_UC_BLANK) { $text .= "\n"; } else { $s = ($curval == $k && $curval !== '') ? "selected='selected'" : ""; $text .= "\n"; } } if (strpos($optlist, "language") !== FALSE && $pref['multilanguage']) { $text .= "\n"; $tmpl = explode(",",e_LANLIST); foreach($tmpl as $lang) { $s = ($curval == $lang) ? " selected='selected'" : ""; $text .= "\n"; } } // Only return the select box if we've ended up with some options if ($text) $text = "\n"; return $text; } /* Generate an ordered array classid=>classname - used for dropdown and check box lists If $just_ids is TRUE, array value is just '1' */ function uc_required_class_list($optlist = '', $just_ids = FALSE) { $ret = array(); if (!$optlist) $optlist = 'public,guest,nobody,member,classes'; // Set defaults to simplify ongoing processing if ($optlist == 'editable') { $temp = array_flip(explode(',',$this->get_editable_classes())); if ($just_ids) return $temp; foreach ($temp as $c => $t) { $temp[$c] = $this->class_tree[$c]['userclass_name']; } return $temp; } $opt_arr = explode(',',$optlist); foreach ($opt_arr as $k => $v) { $opt_arr[$k] = trim($v); } $opt_arr = array_flip($opt_arr); // This also eliminates duplicates which could arise from applying the other options, although shouldn't matter if (isset($opt_arr['force'])) unset($opt_arr['filter']); if (isset($opt_arr['blank'])) { $ret[e_UC_BLANK] = 1; } // Do the 'fixed' classes next foreach ($this->text_class_link as $k => $v) { // if (isset($opt_arr[$k]) || isset($opt_arr['force'])) if (isset($opt_arr[$k])) { $ret[$v] = $just_ids ? '1' : $this->fixed_classes[$v]; } } // Now do the user-defined classes if (isset($opt_arr['classes']) || isset($opt_arr['force'])) { // Display those classes the user is allowed to: // Main admin always sees the lot // a) Mask the 'fixed' user classes which have already been processed // b) Apply the visibility option field ('userclass_visibility') // c) Apply the matchclass option if appropriate foreach($this->class_tree as $uc_id => $row) { if (!array_key_exists($uc_id,$this->fixed_classes) && ( getperms("0") || ( (!isset($optlist["matchclass"]) || check_class($uc_id)) && (!isset($optlist["filter"]) || check_class($row['userclass_visibility'])) ) ) ) { $ret[$uc_id] = $just_ids ? '1' : $this->class_tree[$uc_id]['userclass_name']; } } } /* Above loop slightly changes the display order of earlier code versions. If readonly must be last (after language), delete it from the $text_class_link array, and uncomment the following code if (isset($opt_arr['readonly'])) { $ret[e_UC_READONLY] = $this->class_tree[e_UC_READONLY]['userclass_description']; } */ return $ret; } /* Very similar to r_userclass, but returns a list of check boxes. Doesn't encapsulate it. $fieldname is the name for the array of checkboxes $curval is a comma separated list of class IDs for boxes which are checked. $optlist as for uc_dropdown if $showdescription is TRUE, appends the class description in brackets */ function uc_checkboxes($fieldname, $curval='', $optlist = '', $showdescription = FALSE) { global $pref; $show_classes = $this->uc_required_class_list($optlist); $curArray = explode(",", $curval); // Array of current values $ret = ""; foreach ($show_classes as $k => $v) { if ($k != e_UC_BLANK) { $c = (in_array($k,$curArray)) ? " checked='checked'" : ""; if ($showdescription) $v .= " (".$this->uc_get_classdescription($k).")"; $ret .= "
\n"; } } if (strpos($optlist, "language") !== FALSE && $pref['multilanguage']) { $ret .= "
\n"; $tmpl = explode(",",e_LANLIST); foreach($tmpl as $lang) { $c = (in_array($lang, $curArray)) ? " checked='checked' " : ""; $ret .= "
"; } } return $ret; } /* Next two routines create an indented tree - for example within a select box or a list of check boxes. For each displayed element, the callback routine is called $treename is the name given to the elements where required $callback is a routine used to generate each element; there are two implemented within this class: select (the default) - generates the option list. Text requires to be encapsulated in a tag set - can also be used with multi-select boxes checkbox - generates a set of checkboxes Alternative callbacks can be used to achieve different layouts/styles $current_value is a single class number for single-select dropdown; comma separated array of class numbers for checkbox list or multi-select $optlist works the same as for other class displays */ function vetted_sub_tree($treename, $callback,$listnum,$nest_level,$current_value, $perms) { $ret = ''; $nest_level++; foreach ($this->class_tree[$listnum]['class_children'] as $p) { // Looks like we don't need to differentiate between function and class calls if (isset($perms[$p])) { $ret .= call_user_func($callback,$treename, $p,$current_value,$nest_level); } $ret .= $this->vetted_sub_tree($treename, $callback,$p,$nest_level,$current_value, $perms); } return $ret; } function vetted_tree($treename, $callback='', $current_value='', $optlist = '') { $ret = ''; if (!$callback) $callback=array($this,'select'); $current_value = str_replace(' ','',$current_value); // Simplifies parameter passing for the tidy-minded $perms = $this->uc_required_class_list($optlist,TRUE); // List of classes which we can display if (isset($perms[e_UC_BLANK])) { $ret .= call_user_func($callback,$treename, e_UC_BLANK, $current_value,0); } foreach ($this->class_parents as $p) { if (isset($perms[$p])) { $ret .= call_user_func($callback,$treename, $p,$current_value,0); } $ret .= $this->vetted_sub_tree($treename, $callback,$p,0, $current_value, $perms); } return $ret; } // Callback for vetted_tree - Creates the option list for a selection box function select($treename, $classnum, $current_value, $nest_level) { if ($classnum == e_UC_BLANK) return "\n"; $tmp = explode(',',$current_value); $sel = in_array($classnum,$tmp) ? " selected='selected'" : ''; if ($nest_level == 0) { $prefix = ''; $style = " style='font-weight:bold; font-style: italic;'"; } elseif ($nest_level == 1) { $prefix = '  '; $style = " style='font-weight:bold'"; } else { $prefix = '  '.str_repeat('--',$nest_level-1).'>'; $style = ''; } return "\n"; } // Callback for vetted_tree - displays indented checkboxes with class name only function checkbox($treename, $classnum, $current_value, $nest_level) { if ($classnum == e_UC_BLANK) return ''; $tmp = explode(',',$current_value); $chk = in_array($classnum, $tmp) ? " checked='checked'" : ''; if ($nest_level == 0) { $style = " style='font-weight:bold'"; } else { // $style = " style='text-indent:".(12*$nest_level)."px'"; $style = " style='text-indent:".(1.2*$nest_level)."em'"; } return "
".$this->class_tree[$classnum]['userclass_name']."
\n"; } // Callback for vetted_tree - displays indented checkboxes with class name, and description in brackets function checkbox_desc($treename, $classnum, $current_value, $nest_level) { if ($classnum == e_UC_BLANK) return ''; $tmp = explode(',',$current_value); $chk = in_array($classnum, $tmp) ? " checked='checked'" : ''; if ($nest_level == 0) { $style = " style='font-weight:bold'"; } else { $style = " style='text-indent:".(1.2*$nest_level)."em'"; } return "
".$this->class_tree[$classnum]['userclass_name'].' ('.$this->class_tree[$classnum]['userclass_description'].")
\n"; } /* Return array of all classes, limited according to membership of the userclass_visibility field if $filter is set. Index field - userclass_id Data fields - userclass_name, userclass_description, userclass_editclass */ function uc_get_classlist($filter = FALSE) { $ret = array(); $this->readTree(FALSE); // Make sure we have data foreach ($this->class_tree as $k => $v) { if (!$filter || check_class($filter)) { $ret[$k] = array('userclass_name' => $v, 'userclass_description' => $v['userclass_description'], 'userclass_editclass' => $v['userclass_editclass']); } } return $ret; } function uc_get_classname($id) { if (isset($this->class_tree[$id])) { return $this->class_tree[$id]['userclass_name']; } if (isset($this->fixed_classes[$id])) { return $this->fixed_classes[$id]; } return ''; } function uc_get_classdescription($id) { if (isset($this->class_tree[$id])) { return $this->class_tree[$id]['userclass_description']; } if (isset($this->fixed_classes[$id])) { return $this->fixed_classes[$id]; // Name and description the same for fixed classes } return ''; } function uc_get_classicon($id) { if (isset($this->class_tree[$id])) { return $this->class_tree[$id]['userclass_icon']; } return ''; } function ucGetClassIDFromName($name) { $this->readTree(); // We have all the info - can just search the array foreach ($this->class_tree as $uc => $info) { if ($info['userclass_name'] == $name) { return $uc; } } return FALSE; // not found } /* Return all users in a particular class or set of classes. $classlist is a comma separated list of classes - if the 'predefined' classes are required, they must be included. No spaces allowed $field_list is used to select the returned fields ($user_id is the primary index) ****** Can be verrrrryyyy slow - has to scan the whole user database at present ****** ********* NOT TESTED ********** ***** NOT SURE WHETHER THIS IS REALLY A USER OR A USER CLASS FUNCTION ***** */ function get_users_in_class($classlist, $field_list = 'user_name, user_loginname', $include_ancestors = FALSE, $order_by = 'user_id') { $ret = array(); if ($include_ancestors) $classlist = $this->get_all_user_classes($classlist); $class_regex = "(^|,)(".str_replace(' ','',str_replace(",", "|", $classlist)).")(,|$)"; $qry = "SELECT 'user_id,{$field_list}' FROM `user` WHERE user_class REGEXP '{$class_regex}' ORDER BY '{$order_by}'"; if ($this->sql_r->db_Select_gen($qry)) { while ($row = $this->sql_r->db_Fetch(MYSQL_ASSOC)) { $ret[$row['user_id']] = $row; } } return $ret; } } //======================================================================== // Functions from previous userclass_class handler //======================================================================== // Implemented for backwards compatibility/convenience /* With $optlist you can now specify which classes are shown in the dropdown. All or none can be included, separated by comma (or whatever). Valid options are: public guest nobody member readonly admin main - main admin classes - shows all classes matchclass - if 'classes' is set, this option will only show the classes that the user is a member of language - list of languages. filter - only show those classes where member is in a class permitted to view them - i.e. as the new 'visible to' field force - show all classes (subject to the other options, including matchclass) $mode = 'off' turns off listing of admin/main admin classes unless enabled in $optlist (can probably be deprecated - barely used) */ function r_userclass($fieldname, $curval = 0, $mode = "off", $optlist = "") { // echo "Call r_userclass{$fieldname}, CV: {$curval} opts: {$optlist}
"; global $e_userclass; if ($mode != 'off') { // Handle legacy code if ($optlist) $optlist .= ','; $optlist .= 'admin,main'; if ($mode != 'admin') $optlist .= ',readonly'; } if (!is_object($e_userclass)) $e_userclass = new user_class; return $e_userclass->uc_dropdown($fieldname,$curval,$optlist); } // Very similar to r_userclass, but returns a list of check boxes. (currently only used in newspost.php) // $curval is a comma separated list of class IDs for boxes which are checked. function r_userclass_check($fieldname, $curval = '', $optlist = "") { // echo "Call r_userclass_check: {$curval}
"; global $e_userclass; if (!is_object($e_userclass)) $e_userclass = new user_class; $ret = $e_userclass->uc_checkboxes($fieldname,$curval,$optlist); if ($ret) $ret = "
".$ret."
"; return $ret; } function get_userclass_list() { // echo "Call get_userclass_list
"; global $e_userclass; if (!is_object($e_userclass)) $e_userclass = new user_class; return $e_userclass->uc_get_classlist(); } function r_userclass_name($id) { // echo "Call r_userclass_name
"; global $e_userclass; if (!is_object($e_userclass)) $e_userclass = new user_class; return $e_userclass->uc_get_classname($id); } // Deprecated functions to hopefully be removed function r_userclass_radio($fieldname, $curval = '') { echo "Deprecated function r_userclass_radio not used in core - mutter if you'd like it implemented
"; } //======================================================================== // Admin Class handler - could go into separate file later //======================================================================== class user_class_admin extends user_class { var $field_list = array('userclass_name' => "varchar(100) NOT NULL default ''", 'userclass_description' => "varchar(250) NOT NULL default ''", 'userclass_editclass' => "tinyint(3) unsigned NOT NULL default '0'", 'userclass_parent' => "tinyint(3) unsigned NOT NULL default '0'", 'userclass_accum' => "varchar(250) NOT NULL default ''", 'userclass_visibility' => "tinyint(3) unsigned NOT NULL default '0'", 'userclass_type' =>"tinyint(1) unsigned NOT NULL default '0'", 'userclass_icon' => "varchar(250) NOT NULL default ''" ); // Note - 'userclass_id' intentionally not in this list // Icons to use for graphical tree display // First index - no children, children // Second index - not last item, last item // Third index - closed tree, open tree var $tree_icons = array( ); var $graph_debug = FALSE; // Shows extra info on graphical tree when TRUE function user_class_admin() { $this->user_class(); // Call constructor from ancestor class // Have to initialise the images this way - PHP4 won't take a nested array assignment in the variable list $this->tree_icons = array( FALSE => array( // No children FALSE => array( // Not last item FALSE => '', // Closed tree - don't display TRUE => 'branch.gif' ) , TRUE => array( // Last item FALSE => '', // Closed tree - don't display TRUE => 'branchbottom.gif' ) ), TRUE => array( // children FALSE => array( // Not last item FALSE => 'plus.gif', // Closed tree - option to expand TRUE => 'minus.gif' ) , TRUE => array( // Last item FALSE => 'plusbottom.gif', // Closed tree - option to expand TRUE => 'minusbottom.gif' )) ); } /* Next three routines are used to update the database after adding/deleting a class */ function calc_tree() { // echo "Calc Tree
"; $this->readTree(TRUE); // Make sure we have accurate data foreach ($this->class_parents as $cp) { $rights = array(); $this->rebuild_tree($cp,$rights); // increasing rights going down the tree } } // Internal function, called recursively to rebuild the permissions tree where rights increase going down the tree // $parent is the class number being processed. // $rights is the array of rights accumulated so far in the walk down the tree function rebuild_tree($parent, $rights) { if ($this->class_tree[$parent]['userclass_parent'] == e_UC_NOBODY) { $this->topdown_tree($parent); return; } if ($this->class_tree[$parent]['userclass_type'] == UC_TYPE_GROUP) { echo "Bottom up - skip: {$parent}
"; return; // Probably just stop here for a group class } $rights[] = $parent; $imp_rights = implode(',',$rights); if ($this->class_tree[$parent]['userclass_accum'] != $imp_rights) { $this->class_tree[$parent]['userclass_accum'] = $imp_rights; if (!isset($this->class_tree[$cp]['change_flag'])) $this->class_tree[$parent]['change_flag'] = 'UPDATE'; } foreach ($this->class_tree[$parent]['class_children'] as $cc) { $this->rebuild_tree($cc,$rights); // Recursive call } } // Internal function, called recursively to rebuild the permissions tree where rights increase going up the tree // Returns an array function topdown_tree($our_class) { $rights = array($our_class); // Accumulator always has rights to its own class if ($this->class_tree[$cc] = UC_TYPE_GROUP) return $rights; // Stop rights accumulation at a group foreach ($this->class_tree[$our_class]['class_children'] as $cc) { $rights = array_merge($rights,$this->topdown_tree($cc)); // Recursive call } $rights = array_unique($rights); $imp_rights = implode(',',$rights); if ($this->class_tree[$our_class]['userclass_accum'] != $imp_rights) { $this->class_tree[$our_class]['userclass_accum'] = $imp_rights; $this->class_tree[$our_class]['change_flag'] = 'UPDATE'; } return $rights; } function save_tree() { // echo "Save Tree
"; foreach ($this->class_tree as $tree) { if (isset($tree['change_flag'])) { switch ($tree['change_flag']) { case 'INSERT' : $this->add_new_class($tree); break; case 'UPDATE' : $this->save_edited_class($tree); break; default : continue; } } } } /* Next two routines show a text-based tree with markers to indicate the hierarchy. */ function show_sub_tree($listnum,$marker, $add_class = FALSE) { $ret = ''; $marker = '--'.$marker; foreach ($this->class_tree[$listnum]['class_children'] as $p) { $ret .= $marker.$this->class_tree[$p]['userclass_id'].':'.$this->class_tree[$p]['userclass_name']; if ($add_class) $ret .= " (".$this->class_tree[$p]['userclass_accum'].")"; $ret .= " Children: ".count($this->class_tree[$p]['class_children']); $ret .= "
"; $ret .= $this->show_sub_tree($p,$marker, $add_class); } return $ret; } function show_tree($add_class = FALSE) { $ret = ''; foreach ($this->class_parents as $p) { $ret .= $this->class_tree[$p]['userclass_id'].':'.$this->class_tree[$p]['userclass_name']; if ($add_class) $ret .= " (".$this->class_tree[$p]['userclass_accum'].")"; $ret .= " Children: ".count($this->class_tree[$p]['class_children']); $ret .= "
"; $ret .= $this->show_sub_tree($p,'>', $add_class); } return $ret; } /* Next two routines generate a graphical tree, including option to open/close branches */ function show_graphical_subtree($listnum, $indent_images, $is_last = FALSE) { $num_children = count($this->class_tree[$listnum]['class_children']); $is_open = TRUE; $tag_name = 'uclass_tree_'.$listnum; $ret = "
\n"; foreach ($indent_images as $im) { $ret .= "class icon"; } // If this link has children, wrap the next image in a link and an expand/hide option if ($num_children) { $ret .= "class icon"; $ret .= "\n"; } else { $ret .= "class icon\n"; } $name_line = ''; if ($this->graph_debug) { $name_line = $this->class_tree[$listnum]['userclass_id'].":"; } // if ($this->graph_debug) { $name_line = varset($this->class_tree[$listnum]['userclass_id'], 'XXX').":"; } if ($this->class_tree[$listnum]['userclass_type'] == UC_TYPE_GROUP) { $name_line .= ''.$this->class_tree[$listnum]['userclass_name'].' '.UCSLAN_84; // Highlight groups } else { $name_line .= $this->class_tree[$listnum]['userclass_name']; } if ($this->graph_debug) $name_line .= "[vis:".$this->class_tree[$listnum]['userclass_visibility'].", edit:".$this->class_tree[$listnum]['userclass_editclass']."] = ".$this->class_tree[$listnum]['userclass_accum']; // Next (commented out) line gives a 'conventional' link $ret .= "class icon".$name_line."
"; // $ret .= "class icon".$this->class_tree[$listnum]['userclass_name'].""; //$ret .= "class icon //".$name_line.""; // vertical-align: middle doesn't work! Nor does text-top if ($num_children) { $ret .= "
\n"; $image_level = count($indent_images); if ($is_last) { $indent_images[] = 'linebottom.gif'; } else { $indent_images[] = 'line.gif'; } foreach ($this->class_tree[$listnum]['class_children'] as $p) { $num_children--; if ($num_children) { // Use icon indicating more below $ret .= $this->show_graphical_subtree($p, $indent_images, FALSE); } else { // else last entry on this tree $ret .= $this->show_graphical_subtree($p, $indent_images, TRUE); } } $ret .= "
"; } return $ret; } function show_graphical_tree($show_debug=FALSE) { $this->graph_debug = $show_debug; $indent_images = array(); $ret = "
class icon ".UC_LAN_0."
"; // 'Everyone' link $num_parents = count($this->class_parents); foreach ($this->class_parents as $p) { $num_parents--; $ret .= $this->show_graphical_subtree($p, $indent_images, ($num_parents == 0)); } return $ret; } // Creates an array which contains only DB fields (i.e. strips the added status) function copy_rec($classrec, $inc_id = FALSE) { $ret = array(); if ($inc_id && isset($classrec['userclass_id'])) $ret['userclass_id'] = $classrec['userclass_id']; foreach ($this->field_list as $fl => $val) { if (isset($classrec[$fl])) $ret[$fl] = $classrec[$fl]; } return $ret; } // Return an unused class ID - FALSE if none spare. Misses the predefined classes. function findNewClassID() { $i = 1; // Start by allocating a new class with a number higher than any previously allocated foreach ($this->class_tree as $id => $r) { if ($id < e_UC_SPECIAL_BASE) { $i = max($i,$id); } } $i++; if ($i < e_UC_SPECIAL_BASE) return $i; // Looks like we've had a lot of activity in classes - try and find a gap. for ($i = 1; ($i < e_UC_SPECIAL_BASE); $i++) { if (!isset($this->class_tree[$i])) return $i; } return FALSE; // Just in case all classes assigned! } function add_new_class($classrec) { // echo "Add new class
"; if ($classrec['userclass_type'] == UC_TYPE_GROUP) { // Need to make sure our ID is in the accumulation array $temp = explode(',',$classrec['userclass_accum']); if (!in_array($classrec['userclass_id'], $temp)) { $temp[] = $classrec['userclass_id']; $classrec['userclass_accum'] = implode(',',$temp); } } $this->sql_r->db_Insert('userclass_classes',$this->copy_rec($classrec, TRUE)); $this->clearCache(); } function save_edited_class($classrec) { // echo "Save edited class: ".implode(',', $classrec)."
"; if (!$classrec['userclass_id']) { echo "Programming bungle on save
"; return; } $qry = ''; $spacer = ''; if ($classrec['userclass_type'] == UC_TYPE_GROUP) { // Need to make sure our ID is in the accumulation array $temp = explode(',',$classrec['userclass_accum']); if (!in_array($classrec['userclass_id'], $temp)) { $temp[] = $classrec['userclass_id']; $classrec['userclass_accum'] = implode(',',$temp); } } foreach ($this->field_list as $fl => $val) { if (isset($classrec[$fl])) { $qry .= $spacer."`".$fl."` = '".$classrec[$fl]."'"; $spacer = ", "; } } $this->sql_r->db_Update('userclass_classes', $qry." WHERE `userclass_id`='{$classrec['userclass_id']}'"); $this->clearCache(); } function delete_class($class_id) { if (isset($this->fixed_classes[$class_id])) return FALSE; // Some classes can't be deleted if (!isset($this->class_tree[$class_id])) return FALSE; if (count($this->class_tree[$class_id]['class_children'])) return FALSE; // Can't delete class with descendants foreach ($this->class_tree as $c) { if ($c['userclass_editclass'] == $class_id) return FALSE; if ($c['userclass_visibility'] == $class_id) return FALSE; } if (!$this->sql_r->db_Delete('userclass_classes', "`userclass_id`='{$class_id}'")) return FALSE; $this->clearCache(); $this->readTree(TRUE); // Re-read the class tree return TRUE; } // Certain fields on admin records have constraints on their values. // Checks the passed array, and updates any values which are unacceptable. // Returns TRUE if nothing changed, FALSE if changes made function checkAdminInfo(&$data, $id) { $ret = TRUE; if ($id < e_UC_SPECIAL_BASE) return TRUE; if (isset($data['userclass_parent'])) { if ($data['userclass_parent'] < e_UC_SPECIAL_BASE) { $data['userclass_parent'] = e_UC_NOBODY; $ret = FALSE; } } if (isset($data['userclass_editclass'])) { if ($id == e_UC_MAINADMIN) { if ($data['userclass_editclass'] < e_UC_MAINADMIN) { $data['userclass_editclass'] = e_UC_MAINADMIN; $ret = FALSE; } } elseif ($data['userclass_editclass'] < e_UC_SPECIAL_BASE) { $data['userclass_editclass'] = e_UC_MAINADMIN; $ret = FALSE; } } return $ret; } // Set default tree structure function set_default_structure() { // If they don't exist, we need to create class records for the 'standard' user classes $init_list = array( array('userclass_id' => e_UC_MEMBER, 'userclass_name' => UC_LAN_3, 'userclass_description' => UCSLAN_75, 'userclass_editclass' => e_UC_MAINADMIN, 'userclass_parent' => e_UC_PUBLIC, 'userclass_visibility' => e_UC_MEMBER ), array('userclass_id' => e_UC_ADMINMOD, 'userclass_name' => UC_LAN_8, 'userclass_description' => UCSLAN_74, 'userclass_editclass' => e_UC_MAINADMIN, 'userclass_parent' => e_UC_MAINADMIN, 'userclass_visibility' => e_UC_MEMBER ), array('userclass_id' => e_UC_ADMIN, 'userclass_name' => UC_LAN_5, 'userclass_description' => UCSLAN_76, 'userclass_editclass' => e_UC_MAINADMIN, 'userclass_parent' => e_UC_ADMINMOD, 'userclass_visibility' => e_UC_MEMBER ), array('userclass_id' => e_UC_MAINADMIN, 'userclass_name' => UC_LAN_6, 'userclass_description' => UCSLAN_77, 'userclass_editclass' => e_UC_MAINADMIN, 'userclass_parent' => e_UC_NOBODY, 'userclass_visibility' => e_UC_MEMBER ), array('userclass_id' => e_UC_MODS, 'userclass_name' => UC_LAN_7, 'userclass_description' => UCSLAN_78, 'userclass_editclass' => e_UC_MAINADMIN, 'userclass_parent' => e_UC_ADMINMOD, 'userclass_visibility' => e_UC_MEMBER ) ); foreach ($init_list as $entry) { if ($this->sql_r->db_Select('userclass_classes','*',"userclass_id='".$entry['userclass_id']."' ")) { $this->sql_r->db_Update('userclass_classes', "userclass_parent='".$entry['userclass_parent']."', userclass_visibility='".$entry['userclass_visibility']."' WHERE userclass_id='".$entry['userclass_id']."'"); } else { $this->add_new_class($entry); } } } function clearCache() { global $e107; $e107->ecache->clear_sys(UC_CACHE_TAG); } } //======================================================================== // Legacy Admin Class handler - maybe add to admin class //======================================================================== // class_add() - called only from userclass2.php // class_remove() - called only from userclass2.php // class_create() - called only from forum update routines - could probably go class e_userclass { function class_add($cid, $uinfoArray) { global $tp; $sql2 = new db; foreach($uinfoArray as $uid => $curclass) { if ($curclass) { $newarray = array_unique(array_merge(explode(',', $curclass), array($cid))); $new_userclass = implode(',', $newarray); } else { $new_userclass = $cid; } $sql2->db_Update('user', "user_class='".$tp -> toDB($new_userclass, true)."' WHERE user_id=".intval($uid)); } } function class_remove($cid, $uinfoArray) { global $tp; $sql2 = new db; foreach($uinfoArray as $uid => $curclass) { $newarray = array_diff(explode(',', $curclass), array('', $cid)); $new_userclass = implode(',', $newarray); $sql2->db_Update('user', "user_class='".$tp -> toDB($new_userclass, true)."' WHERE user_id=".intval($uid)); } } // Mostly for upgrades? // Create a new user class, with a specified prefix to the name // $ulist - comma separated list of user names to be added function class_create($ulist, $class_prefix = "NEW_CLASS_", $num = 0) { global $sql; $varname = "uc_".$ulist; if($ret = getcachedvars($varname)) { return $ret; } $ul = explode(",", $ulist); array_walk($ul, array($this, 'munge')); $qry = " SELECT user_id, user_class from #user AS u WHERE user_name = ".implode(" OR user_name = ", $ul); if($sql->db_Select_gen($qry)) { while($row = $sql->db_Fetch()) { $idList[$row['user_id']] = $row['user_class']; } while($sql->db_Count("userclass_classes","(*)","WHERE userclass_name = '".strtoupper($class_prefix.$num)."'")) { $num++; } $newname = strtoupper($class_prefix.$num); $i = 1; while ($sql->db_Select('userclass_classes', '*', "userclass_id='".intval($i)."' ") && $i < 240) { $i++; } if ($i < 240) // Give a bit of headroom - we're allocating 'system' classes downwards from 255 { $sql->db_Insert("userclass_classes", "{$i}, '{$newname}', 'Auto_created_class', 254"); $this->class_add($i, $idList); // Add users cachevars($varname, $i); return $i; } } } function munge(&$value, &$key) { $value = "'".trim($value)."'"; } } ?>