/** display the content of the sitemap linked to node $node_id * * there are three different variations (depends on configuration parameter 'scope'): * * - 0 (small): only show a map of the tree in the current area $area_id * - 1 (medium): show a list of available areas followed by the map of the current area $area_id * - 2 (large): show the maps of all available areas * * The default is 0 (small). * * @param object &$theme collects the (html) output * @param int $area_id identifies the area where $node_id lives * @param int $node_id the node to which this module is connected * @param array $module the module record straight from the database * @return bool TRUE on success + output via $theme, FALSE otherwise */ function sitemap_view(&$theme, $area_id, $node_id, $module) { global $USER; // // 1 -- determine scope of sitemap: 0=small, 1=medium, 2=large // $table = 'sitemaps'; $fields = array('header', 'introduction', 'scope'); $where = array('node_id' => intval($node_id)); $record = db_select_single_record($table, $fields, $where); if ($record === FALSE) { logger(sprintf('%s(): error retrieving configuration: %s', __FUNCTION__, db_errormessage())); $scope = 0; $header = ''; $introduction = ''; } else { $scope = intval($record['scope']); $header = trim($record['header']); $introduction = trim($record['introduction']); } // // 2 -- compute a list of areas to process (could be just 1) // // 2A -- retrieve all areas, including those out of bounds for this user if (($all_areas = get_area_records()) === FALSE) { logger(sprintf('%s(): huh? cannot get area records: %s', __FUNCTION__, db_errormessage())); return FALSE; // shouldn't happen } // 2B -- narrow down the selection (active, (private) access allowed, within scope) $areas = array(); foreach ($all_areas as $id => $area) { if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) { if ($scope == 2 || $scope == 1 || $scope == 0 && $id == $area_id) { $title = $area['title']; $params = array('area' => $id); $href = was_node_url(NULL, $params, $title, $theme->preview_mode); $areas[$id] = html_a($href, NULL, NULL, $title); } } } unset($all_areas); // $areas now holds all areas that we should to process if (sizeof($areas) <= 0) { logger(sprintf('%s(): weird, no areas to process; bailing out', __FUNCTION__)); return FALSE; // shouldn't happen } // // 3 -- maybe output a header and an introduction // if (!empty($header)) { $theme->add_content('<h2>' . $header . '</h2>'); } if (!empty($introduction)) { $theme->add_content($introduction); } // // 4 - Actually output a sitemap by walking the tree once for every elegible area // foreach ($areas as $id => $area_anchor) { if ($scope == 1 && $area_id != $id) { // 1=medium only shows area map of $area_id (and an area list lateron) continue; } // 4A -- output a clickable area title $theme->add_content('<h2>' . $area_anchor . '</h2>'); // 4B -- fetch the tree for this area... $tree = tree_build($id); tree_visibility($tree[0]['first_child_id'], $tree); // 4C -- ...and walk the tree sitemap_tree_walk($theme, $tree[0]['first_child_id'], $tree); unset($tree); } if ($scope == 1) { $theme->add_content('<h2>' . t('sitemap_available_areas', 'm_sitemap') . '</h2>'); $theme->add_content('<ul>'); foreach ($areas as $id => $area_anchor) { $theme->add_content('<li>' . $area_anchor); } $theme->add_content('</ul>'); } return TRUE; // indicate success }
/** validate and massage the user-supplied data path * * this checks the directory path the user entered, * returns TRUE if the tests are passed. * * There three places from which snapshots can be retrieved: * - /areas/aaa * - /users/uuu * - /groups/ggg * * That is: the path should at least contain 2 levels (and possibly more). * In other words: a bare '/' is not enough and neither are bare '/areas', * '/users' or '/groups'. And of course the directory should already exist * in the file systen under $CFG->datadir. * * Various tests are done: * - the selected area directory must be active * - if the selected area is private, * $USER must have intranet access for this area, OR * the selected area must be the same as the area in which $node_id resides * - the selected user directory must be the $USER's, OR * the $USER has access to the account manager (able to manipulate ALL users' directories) * - the selected group directory must be from a group the $USER is a member of, OR * the $USER has access to the account manager (able to manipulate ALL groups' directories) * * If all tests succeed, we may want to warn the user in the case that the * file location is in a different (and public) area than the node holding the snapshots module. * However, this is a warning only. * * Finally, we reconstruct the path in such a way that it starts with a slash * and does NOT end with a slash. This is done by changing the content of the $item parameter. * * @param array &$item holds the field definition from the $dialogdef for the snapshots_path * @param int $area_id the area in which we are editing a snapshot module configuration * @param int $node_id the node to which the snapshot module is connected (unused) * @return bool TRUE if valid path, otherwise FALSE + messages in dialogdef * @todo should the user / group really be active here? If not, the images will fail in file.php * but that may leak information about inactive users. Hmmm... * @todo we should use a different error message as soon as it is available in was.php, * eg. 'validate_bad_directory' (much like 'validate_bad_filename'). */ function snapshots_check_path(&$item, $area_id, $node_id) { global $USER, $CFG; $warning = ''; $invalid = FALSE; $path_components = explode('/', trim(strtr($item['value'], '\\', '/'), '/')); if (sizeof($path_components) < 2 || in_array('..', $path_components)) { $invalid = TRUE; } else { switch ($path_components[0]) { case 'areas': $fields = array('area_id', 'is_private', 'title'); $where = array('is_active' => TRUE, 'path' => $path_components[1]); $table = 'areas'; if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { // area doesn't exist or is inactive $invalid = TRUE; } elseif (db_bool_is(TRUE, $record['is_private'])) { // specified area is private if (intval($record['area_id']) != $area_id || !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $record['area_id'])) { // this private area is NOT the one where $node_id resides OR this user is denied access $invalid = TRUE; } } else { // specified area is public if (intval($record['area_id']) != $area_id) { // but it is not the same as the one where $node_id resides: go warn user eventually! $params = array('{AREANAME}' => htmlspecialchars($record['title'])); $warning = t('warning_different_area', 'm_snapshots', $params); } } break; case 'users': if (!$USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER) && $path_components[1] != $USER->path) { $invalid = TRUE; } if ($path_components[1] == $USER->path) { $warning = t('warning_personal_directory', 'm_snapshots'); } break; case 'groups': if (!$USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) { $usergroups = get_user_groups($USER->user_id); $is_member = FALSE; foreach ($usergroups as $group_id => $usergroup) { if ($usergroup['path'] == $path_components[1]) { $is_member = TRUE; break; } } if (!$is_member) { $invalid = TRUE; } } break; default: $invalid = TRUE; break; } } if (!$invalid) { $path = '/' . implode('/', $path_components); if (!is_dir($CFG->datadir . $path)) { $invalid = TRUE; } } if ($invalid) { $fname = str_replace('~', '', $item['label']); $params = array('{PATH}' => htmlspecialchars($item['value'])); $error_message = sprintf('%s: %s', $fname, t('invalid_path', 'admin', $params)); ++$item['errors']; $item['error_messages'][] = $error_message; return FALSE; } if ($warning != '') { $item['warnings'] = 0; ++$item['warnings']; $item['warning_messages'] = $warning; } $item['value'] = $path; return TRUE; }
/** main program for visitors * * this routine is called from /index.php. It is the main program for visitors. * * @return void page sent to the browser * @todo cleanup login/logout-code */ function main_index() { global $USER; global $CFG; global $LANGUAGE; /** initialise the program, setup database, read configuration, etc. */ require_once $CFG->progdir . '/init.php'; initialise(); was_version_check(); // this never returns if versions don't match // TODO: cleanup like in main_admin() // handle login/logout/continuation so we quickly find out which user is calling if (isset($_GET['logout'])) { /** loginlib.php contains both login- and logout-routines */ require_once $CFG->progdir . '/lib/loginlib.php'; was_logout(); // may or may not return here } elseif (isset($_GET['login'])) { /** loginlib.php contains both login- and logout-routines */ require_once $CFG->progdir . '/lib/loginlib.php'; was_login(magic_unquote($_GET['login'])); // may or may not return here } elseif (isset($_COOKIE[$CFG->session_name])) { /** dbsessionlib.php contains our own database based session handler */ require_once $CFG->progdir . '/lib/dbsessionlib.php'; dbsession_setup($CFG->session_name); if (dbsession_exists(magic_unquote($_COOKIE[$CFG->session_name]))) { session_start(); } } // At this point we either have a valid session with a logged-in user // (indicated via existence of $_SESSION) or we are dealing with an anonymous // visitor with non-existing $_SESSION. Keep track of the number of calls // this user makes (may be logged lateron on logout). if (isset($_SESSION)) { if (!isset($_SESSION['session_counter'])) { // first time after login, record start time of session $_SESSION['session_counter'] = 1; $_SESSION['session_start'] = strftime("%Y-%m-%d %T"); } else { $_SESSION['session_counter']++; } } // Now is the time to create a USER object, even when the visitor is just a passerby // because we can then determine easily if a visitor is allowed certain things, e.g. // view a protected area or something /** useraccount.class.php is used to define the USER object */ require_once $CFG->progdir . '/lib/useraccount.class.php'; if (isset($_SESSION) && isset($_SESSION['user_id'])) { $USER = new Useraccount($_SESSION['user_id']); $USER->is_logged_in = TRUE; $_SESSION['language_key'] = $LANGUAGE->get_current_language(); // remember language set via _GET or otherwise } else { $USER = new Useraccount(); $USER->is_logged_in = FALSE; } // Check for the special preview-mode // This allows a webmaster to preview a page in the correct environment (theme) // even when the page is under embargo. Note that the node_id and area_id are // retrieved from the session; the user only has a cryptic preview-code. // See pagemanagerlib.php for more information (function task_page_preview()). $in_preview_mode = FALSE; if ($USER->is_logged_in) { $preview_code_from_url = get_parameter_string('preview'); if (!is_null($preview_code_from_url) && isset($_SESSION['preview_salt']) && isset($_SESSION['preview_node'])) { $hash = md5($_SESSION['preview_salt'] . $_SESSION['preview_node']); if ($hash === $preview_code_from_url) { $node_id = intval($_SESSION['preview_node']); $area_id = intval($_SESSION['preview_area']); $area = db_select_single_record('areas', '*', array('area_id' => $area_id)); if ($area === FALSE) { logger("Fatal error 070: cannot preview node '{$node_id}' in area '{$area_id}'"); error_exit('070'); } else { $tree = tree_build($area_id); $in_preview_mode = TRUE; } } } } if ($in_preview_mode == FALSE) { $requested_area = get_requested_area(); $requested_node = get_requested_node(); $req_area_str = is_null($requested_area) ? "NULL" : strval($requested_area); $req_node_str = is_null($requested_node) ? "NULL" : strval($requested_node); if (($area = calculate_area($requested_area, $requested_node)) === FALSE) { logger("Fatal error 080: no valid area (request: area='{$req_area_str}', node='{$req_node_str}')"); error_exit('080'); // no such area } $area_id = intval($area['area_id']); // If $USER has no permission to view area $area_id, we simply bail out. // Rationale: if the user is genuine, she knows about logging in first. // If the user is NOT logged in and tries to view a protected area, I'd consider // it malicious, and in that case I won't even confirm the existence of // the requested area. (If a cracker simply tries areas 0,1,.. and sometimes is greeted // with 'please enter credentials' and sometimes with 'area does not exist', this // provides information to the cracker. I don't want that). Note that the error code // is the same as the one for non-existing area. In other words: for an unauthorised // visitor an existing private area is just as non-existent as a non-existing public area. if (db_bool_is(TRUE, $area['is_private']) && !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $area_id)) { logger(sprintf("Fatal error 080: no view permissions for area '%d' (request: area='%s', node='%s')", $area_id, $req_area_str, $req_node_str)); error_exit('080'); // no such area } // still here? // then we've got a valid $area_id and corresponding $area record. // now we need to figure out which $node_id to use $tree = tree_build($area_id); if (($node_id = calculate_node_id($tree, $area_id, $requested_node)) === FALSE) { logger(sprintf("Fatal error 080: no valid node within area '%d' (request: area='%s', node='%s')", $area_id, $req_area_str, $req_node_str)); error_exit('080'); // no such area } } // At this point we have the following in our hands // - a valid $area_id // - a valid $node_id // - the complete tree from area $area_id in $tree // - the area record from database in $area // - the node record from database in $tree[$node_id]['record'] // - a flag that signals preview mode in $in_preview_mode // We are on our way to generate a full page with content and all, // but otoh we MIGHT be in the middle of a redirect, so we may have to // leave without showing anything at all... if (!empty($tree[$node_id]['record']['link_href'])) { update_statistics($node_id); if (isset($_SESSION)) { session_write_close(); } redirect_and_exit(htmlspecialchars($tree[$node_id]['record']['link_href'])); // exit; redirect_and_exit() never returns } /** themelib contains the theme factory */ require_once $CFG->progdir . '/lib/themelib.php'; // And now we know about the $area, we can carry on determining which $theme to use. // $theme = theme_factory($area['theme_id'], $area_id, $node_id); if ($theme === FALSE) { logger("Fatal error 090: cannot setup theme '{$area['theme_id']}' in area '{$area_id}'"); error_exit('090'); } // Tell the theme about the preview mode $theme->set_preview_mode($in_preview_mode); // Now all we need to do is let the module connected to node $node_id generate output $module_id = $tree[$node_id]['record']['module_id']; module_view($theme, $area_id, $node_id, $module_id); // Remember this visitor update_statistics($node_id); // Finally, send output to user $theme->send_output(); if (isset($_SESSION)) { session_write_close(); } // done! exit; }
/** calculate an ordered list of filenames to try for translation of phrases * * WAS uses a separate language file for every text domain; * basically the name of the text domain is the name of the * file without the .php-extension. However, in order to prevent * name clashes, modules and themes and addons have their own * prefix: 'm_' for modules and 't_' for themes and 'a_' for * addons. * * The language translations for the installer are based on more or * less the same trick: the prefix 'i_' identifies files in the * directory /program/install/languages. * * This trick with prefixing leads to the following search orders * for generic phrases and module-, theme- and addon-specific phrases. * * Example 1: phrases with $domain='login': * {$CFG->progdir}/languages/{$language_key}/login.php * {$CFG->datadir}/languages/{$language_key}/login.php * * Example 2: phrases with $domain='m_guestbook': * {$CFG->progdir}/modules/guestbook/languages/{$language_key}/guestbook.php * {$CFG->progdir}/languages/{$language_key}/m_guestbook.php * {$CFG->datadir}/languages/{$language_key}/m_guestbook.php * * Example 3: phrases with $domain='login' and a hint in $location_hint: * {$location_hint}/{$language_key}/login.php * {$CFG->datadir}/languages/{$language_key}/login.php * * Example 4: phrases with $domain='m_guestbook' and a hint in $location_hint: * {$location_hint}/{$language_key}/guestbook.php * {$location_hint}/{$language_key}/m_guestbook.php * {$CFG->datadir}/languages/{$language_key}/m_guestbook.php * * Example 5: phrases with $domain='i_demodata': * {$CFG->progdir}/install/languages/{$language_key}/demodata.php * {$CFG->datadir}/languages/{$language_key}/i_demodata.php * * @param string $full_domain indicates the text domain including optional module/theme/addon prefix * @param string $location_hint hints at a location of language file(s) * @param string $language_key target language * @return array an ordered list of filenames * @uses $CFG */ function get_filenames_to_try($full_domain, $location_hint, $language_key) { global $CFG; static $extensions = array('m_' => 'modules', 't_' => 'themes', 'a_' => 'addons'); $filenames = array(); // Minimal validation of location hint: this directory should at least exist $directory = !empty($location_hint) && is_dir($location_hint) ? $location_hint : ''; // Modules/themes/addons have a 2-char prefix in their full_domain. // If this is the case, we start with a language path as close to the // module/theme/addon as possible _or_ in the hint location. $prefix = substr($full_domain, 0, 2); $domain = substr($full_domain, 2); if (isset($extensions[$prefix])) { $extension = $extensions[$prefix]; if (empty($directory)) { $filenames[] = $CFG->progdir . '/' . $extension . '/' . $domain . '/languages/' . $language_key . '/' . $domain . '.php'; } else { $filenames[] = $directory . '/' . $language_key . '/' . $domain . '.php'; } } elseif ($prefix == 'i_') { if (empty($directory)) { $filenames[] = $CFG->progdir . '/install/languages/' . $language_key . '/' . $domain . '.php'; } else { $filenames[] = $directory . '/' . $language_key . '/' . $domain . '.php'; } } if (empty($directory)) { $filenames[] = $CFG->progdir . '/languages/' . $language_key . '/' . $full_domain . '.php'; } else { $filenames[] = $directory . '/' . $language_key . '/' . $full_domain . '.php'; } // If this language has the flag 'dialect_in_file' set, we try $CFG->datadir/languages too if (db_bool_is(TRUE, $this->languages[$language_key]['dialect_in_file'])) { $filenames[] = $CFG->datadir . '/languages/' . $language_key . '/' . $full_domain . '.php'; } return $filenames; }
/** construct a clickable icon to set the default area * * the 'default' icon is displayed for the default area, the * 'non-default' icon for all others. The user is allowed to make the * area the default area if the user has edit permissions for both the * old and the new default area. * * @param int $area_id * @param array &$areas records with area information of all areas * @return string ready-to-use A-tag * @uses $CFG * @uses $USER * @uses $WAS_SCRIPT_NAME */ function get_icon_home($area_id, &$areas) { global $CFG, $WAS_SCRIPT_NAME, $USER; // 1A -- check out permissions: we need them for this area AND the current default area $user_has_permission = FALSE; if ($USER->has_area_permissions(PERMISSION_AREA_EDIT_AREA, $area_id)) { $user_has_permission = TRUE; foreach ($areas as $area) { if (db_bool_is(TRUE, $area['is_default'])) { $user_has_permission = $USER->has_area_permissions(PERMISSION_AREA_EDIT_AREA, $area['area_id']); break; } } } // 1B -- construct a title/mouseover depending on permissions/current default area if (!$user_has_permission) { $title = t('icon_area_default_access_denied', 'admin'); } elseif (db_bool_is(TRUE, $areas[$area_id]['is_default'])) { $title = t('icon_area_is_default', 'admin'); } else { $title = t('icon_area_default', 'admin'); } // 2 -- construct the icon (image or text) if (db_bool_is(TRUE, $areas[$area_id]['is_default'])) { $icon = 'startsection'; $alt = t('icon_area_default_alt', 'admin'); $text = t('icon_area_default_text', 'admin'); } else { $icon = 'not_startsection'; $alt = t('icon_area_not_default_alt', 'admin'); $text = t('icon_area_not_default_text', 'admin'); } $anchor = $this->output->skin->get_icon($icon, $title, $alt, $text); // 3 -- construct the A tag $a_params = $this->a_param(AREAMANAGER_CHORE_SET_DEFAULT, $area_id); $a_attr = array('name' => 'area' . strval($area_id), 'title' => $title); if (!$user_has_permission) { $a_attr['class'] = 'dimmed'; } return html_a($WAS_SCRIPT_NAME, $a_params, $a_attr, $anchor); }
/** retrieve an array with node records straight from the database * * this routine constructs a list of 0, 1 or more node records based * on the $node_id provided by the caller. The node records are * retrieved from the database. * * This routine takes care of the showstoppers like embargo and * expiry and also access permissions to the area. We can not * be sure if the user actually has access to a page until we * are have checked to area in which the node $node_id resides. * This is an extra test compared to * {@link aggregator_view_get_node_from_tree()} above. * * @param int $node_id identifies page or section to evaluate * @param array &$config points to the aggregator configuration * @param array &$modules points to array with supported modules * @return array ordered list of nodes to aggregate (could be empty) */ function aggregator_view_get_node_from_db($node_id, &$config, &$modules) { global $USER; $nodes = array(); $table = 'nodes'; $fields = '*'; $order = $config['reverse_order'] ? 'sort_order DESC' : 'sort_order'; $where = array('node_id' => intval($node_id)); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s(): error retrieving node record: %s', __FUNCTION__, db_errormessage())); return $nodes; } $now = strftime("%Y-%m-%d %T"); // don't show expired nodes or nodes under embargo if ($now < $record['embargo'] || $record['expiry'] < $now) { return $nodes; } // don't show private or inactive areas to random strangers $areas = get_area_records(); $area_id = intval($record['area_id']); if (db_bool_is(FALSE, $areas[$area_id]['is_active']) || db_bool_is(TRUE, $areas[$area_id]['is_private']) && !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $area_id)) { return $nodes; } // if it was but a plain page we're done (even if not htmlpage or snapshots) if (db_bool_is(TRUE, $record['is_page'])) { $module_id = intval($record['module_id']); if (isset($modules[$module_id])) { $nodes[] = $record; } return $nodes; } // mmm, must have been a section (but at least in the correct area) // go get the pages in this section in this area $where = array('parent_id' => $node_id, 'area_id' => $area_id, 'is_page' => TRUE); if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) { logger(sprintf('%s(): error retrieving node records: %s', __FUNCTION__, db_errormessage())); return $nodes; } $counter = 0; foreach ($records as $record) { // don't show expired nodes or nodes under embargo if ($now < $record['embargo'] || $record['expiry'] < $now) { continue; } $module_id = intval($record['module_id']); if (isset($modules[$module_id])) { $nodes[] = $record; if (++$counter >= $config['items']) { break; } } } return $nodes; }
/** build a tree of all nodes in an area * * this routine constructs a tree-structure of all nodes in area $area_id in much * the same way as {@link tree_build()} does. However, in this routine we keep the * cargo limited to a minimum: the fields we retrieve from the nodes table and * store in the tree are: * - node_id * - parent_id * - is_page * - title * - link_text * - module_id * Also, the tree is not cached because that does not make sense here: we only * use it to construct a dialogdef and that is a one-time operation too. * * @parameter int $area_id the area for which to build the tree * @param int $acl_id the primary acl_id (used for both users and groups) * @param array|null $related_acls an array with related acls for this user keyed by 'acl_id' or NULL for group acls * @return array ready to use tree structure w/ permissions */ function tree_build($area_id) { // 1 -- Start with 'special' node 0 is root of the tree $tree = array(0 => array('node_id' => 0, 'parent_id' => 0, 'prev_sibling_id' => 0, 'next_sibling_id' => 0, 'first_child_id' => 0, 'is_page' => FALSE, 'title' => '', 'link_text' => '', 'module_id' => 0)); $where = array('area_id' => intval($area_id)); $order = array('CASE WHEN (parent_id = node_id) THEN 0 ELSE parent_id END', 'sort_order', 'node_id'); $fields = array('node_id', 'parent_id', 'is_page', 'title', 'link_text', 'module_id'); $records = db_select_all_records('nodes', $fields, $where, $order, 'node_id'); // 2 -- step through all node records and copy the relevant fields if ($records !== FALSE) { foreach ($records as $record) { $node_id = intval($record['node_id']); $parent_id = intval($record['parent_id']); $is_page = db_bool_is(TRUE, $record['is_page']); if ($parent_id == $node_id) { // top level $parent_id = 0; } $tree[$node_id] = array('node_id' => $node_id, 'parent_id' => $parent_id, 'prev_sibling_id' => 0, 'next_sibling_id' => 0, 'first_child_id' => 0, 'is_page' => $is_page, 'title' => $record['title'], 'link_text' => $record['link_text'], 'module_id' => intval($record['module_id'])); } } unset($records); // free memory // 3 -- step through all collected records and add links to childeren and siblings $prev_node_id = 0; $sort_order = 0; foreach ($tree as $node_id => $node) { $parent_id = $node['parent_id']; if (!isset($tree[$parent_id])) { logger("aclmanager: node '{$node_id}' is an orphan because parent '{$parent_id}' does not exist in tree[]"); } elseif ($parent_id == $tree[$prev_node_id]['parent_id']) { $tree[$prev_node_id]['next_sibling_id'] = $node_id; $tree[$node_id]['prev_sibling_id'] = $prev_node_id; } else { $tree[$parent_id]['first_child_id'] = $node_id; } $prev_node_id = $node_id; } // 4 -- 'root node' 0 is a special case, the top level nodes are in fact childeren, not siblings $tree[0]['first_child_id'] = $tree[0]['next_sibling_id']; $tree[0]['next_sibling_id'] = 0; // 5 -- done! return $tree; }
/** generate a list of areas for use in a dropdown list (for moving a node to another area) * * this creates an array containing a list of areas to which the user * is allowed to move a node. Permissions for * moving a node is a combination of permissions for deleting a node from the * current area, and adding a node to the target area. The current area * $this->area_id is always in the list, because even if the user isn't * allowed to move a node to somewhere else, she is at least allowed to leave * the node in the area it currently is in. Therefore the option for the * current area MUST be possible. * * We sepcifically check for these permissions: * PERMISSION_AREA_ADD_PAGE or PERMISSION_AREA_ADD_SECTION * and not PERMISSION_NODE_ADD_PAGE or PERMISSION_NODE_ADD_SECTION * because the target of the move is always the top level, and not some * (sub)section. * * @param int $node_id the node for which we are building this picklist * @param bool $is_page TRUE if this concerns a page, FALSE for a section * @return array ready for use as an options array in a listbox or radiobuttons */ function get_options_area($node_id, $is_page) { global $USER; $options = array(); $can_drop_current = $this->permission_delete_node($node_id, $is_page); $permissions = $is_page ? PERMISSION_AREA_ADD_PAGE : PERMISSION_AREA_ADD_SECTION; foreach ($this->areas as $area_id => $area) { if ($this->area_id == $area_id || $can_drop_current && $USER->has_area_permissions($permissions, $area_id)) { $is_active = db_bool_is(TRUE, $area['is_active']); $a_area = array('{AREA}' => $area_id, '{AREANAME}' => $area['title']); if (db_bool_is(TRUE, $area['is_private'])) { $option_text = t($is_active ? 'options_private_area' : 'options_private_area_inactive', 'admin', $a_area); } else { $option_text = t($is_active ? 'options_public_area' : 'options_public_area_inactive', 'admin', $a_area); } $options[$area_id] = array('option' => $option_text, 'title' => $area['title'], 'class' => 'level0'); } } return $options; }
/** construct a zipfile with the current source and stream it to the visitor * * this routine streams a ZIP-archive to the visitor with either the current * websiteatschool program code or the selected manual. This routine is necessary * to comply with the provisions of the program license which basically says that the * source code of the running program must be made available. * * Note that it is not strictly necessary to also provide the manual, but this * routine can do that nevertheless. * * Note that we take special care not to download the (private) data directory * $CFG->datadir. Of course the datadirectory should live outside the document * root and certainly outside the /program directory tree, but accidents will * happen and we don't want to create a gaping security hole. * * If there are severe errors (e.g. no manual is available for download or an invalid * component was specified) the program exist immediately with a 404 not found error. * Otherwise the ZIP-archive is streamed to the user. If all goes well, we return TRUE, * if there were errors we immediately return TRUE (without finishing the task at hand * other than a perhasp futile attempt to properly close the ZIP-archive). The last * error message from the Zip is logged. * * @param string $component either 'program' or 'manual' or 'languages' * @return void|bool Exit with 404 not found, OR TRUE and generated ZIP-file sent to user OR FALSE on error * @uses download_source_tree() */ function download_source($component) { global $CFG; global $LANGUAGE; $time_start = microtime(); // // Step 0 -- decide what needs to be done // switch ($component) { case 'program': $files = array('index.php', 'admin.php', 'cron.php', 'file.php', 'config-example.php'); $directories = array('program' => $CFG->progdir); $excludes = array(realpath($CFG->datadir), realpath($CFG->progdir . '/manuals')); $archive = 'websiteatschool-program.zip'; break; case 'manual': $language = $LANGUAGE->get_current_language(); $manuals = $CFG->progdir . '/manuals'; if (!is_dir($manuals . '/' . $language)) { if (!is_dir($manuals . '/en')) { logger(sprintf("Failed download 'websiteatschool/manual/%s': 404 Not Found", $language)); error_exit404("websiteatschool/{$component}"); } else { $language = 'en'; } } $files = array(); $directories = array('program/manuals/' . $language => $manuals . '/' . $language); $excludes = array(realpath($CFG->datadir)); $archive = sprintf('websiteatschool-manual-%s.zip', $language); break; case 'languages': $files = array(); $directories = array(); $excludes = array(); $archive = 'websiteatschool-languages.zip'; $languages = $LANGUAGE->retrieve_languages(); foreach ($languages as $language_key => $language) { if (db_bool_is(TRUE, $language['is_active']) && db_bool_is(TRUE, $language['dialect_in_file'])) { $directories['languages/' . $language_key] = $CFG->datadir . '/languages/' . $language_key; } } if (sizeof($directories) < 1) { logger(sprintf("Failed download websiteatschool/%s': 404 Not Found", $component)); error_exit404('websiteatschool/' . $component); } break; default: logger(sprintf("Failed download websiteatschool/%s': 404 Not Found", $component)); error_exit404('websiteatschool/' . $component); break; } // // Step 1 -- setup Ziparchive // include_once $CFG->progdir . '/lib/zip.class.php'; $zip = new Zip(); $comment = $CFG->www; if (!$zip->OpenZipstream($archive, $comment)) { $elapsed = diff_microtime($time_start, microtime()); logger(sprintf("Failed download '%s' (%0.2f seconds): %s", $archive, $elapsed, $zip->Error)); return FALSE; } // // Step 2 -- add files in the root directory (if any) // if (sizeof($files) > 0) { foreach ($files as $file) { $path = $CFG->dir . '/' . $file; if (!file_exists($path)) { logger(sprintf("%s(): missing file '%s' in archive '%s'", __FUNCTION__, $path, $archive), WLOG_DEBUG); $data = sprintf('<' . '?' . 'php echo "%s: file was not found"; ?' . '>', $file); $comment = sprintf('%s: missing', $file); if (!$zip->AddData($data, $file, $comment)) { $elapsed = diff_microtime($time_start, microtime()); logger(sprintf("Failed download '%s' (%0.2f seconds): %s", $archive, $elapsed, $zip->Error)); $zip->CloseZip(); return FALSE; } } else { if (!$zip->AddFile($path, $file)) { $elapsed = diff_microtime($time_start, microtime()); logger(sprintf("Failed download '%s' (%0.2f seconds): %s", $archive, $elapsed, $zip->Error)); $zip->CloseZip(); return FALSE; } } } } // // Step 3 -- add directories to archive // foreach ($directories as $vpath => $path) { if (!download_source_tree($zip, $path, $vpath, $excludes)) { $elapsed = diff_microtime($time_start, microtime()); logger(sprintf("Failed download '%s' (%0.2f seconds): %s", $archive, $elapsed, $zip->Error)); $zip->CloseZip(); return FALSE; } } // // Step 4 -- we're done // if (!$zip->CloseZip()) { $elapsed = diff_microtime($time_start, microtime()); logger(sprintf("Failed download '%s' (%0.2f seconds): %s", $archive, $elapsed, $zip->Error)); return FALSE; } logger(sprintf("Download '%s' (%0.2f seconds): success", $archive, diff_microtime($time_start, microtime()))); return TRUE; }
/** construct a Theme object * * this stores the information about this theme from the database. * Also, we construct/read the tree of nodes for this area $area_id. This * information will be used lateron when constructing the navigation. * The node to display is $node_id. * * Also, we prepare a list of areas where the current user is allowed to go. * This is handy when constructing a jumpmenu and doing it here saves a trip * to the database lateron in {@link get_jumpmenu()}. * * @param array $theme_record the record straight from the database * @param int $area_id the area of interest * @param int $node_id the node that will be displayed * @return void */ function Theme($theme_record, $area_id, $node_id) { global $USER, $CFG; $charset = 'UTF-8'; $content_type = 'text/html; charset=' . $charset; $this->add_http_header('Content-Type: ' . $content_type); $this->theme_record = $theme_record; $this->theme_id = intval($theme_record['theme_id']); $this->area_id = intval($area_id); $this->jumps = array(); // extract areas information and // - grab a copy of the full area_record 'for future reference', and // - make a list of areas accessible for this user (for the area jumpmenu) if (($areas = get_area_records()) !== FALSE) { $this->area_record = $areas[$this->area_id]; foreach ($areas as $id => $area) { if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) { $this->jumps[$id] = $area['title']; } } } else { $this->area_record = array('area_id' => $this->area_id, 'title' => '?'); logger(sprintf('constructor %s(): cannot get list of areas: %s', __FUNCTION__, db_errormessage()), WLOG_DEBUG); } $this->node_id = intval($node_id); $this->tree = $this->construct_tree($this->area_id); $this->node_record = $this->tree[$node_id]['record']; $this->config = $this->get_properties($this->theme_id, $this->area_id); $this->add_meta_http_equiv(array('Content-Type' => $content_type, 'Content-Script-Type' => 'text/javascript', 'Content-Style-Type' => 'text/css')); $this->title = $this->area_record['title']; $this->add_meta(array('MSSmartTagsPreventParsing' => 'TRUE', 'generator' => 'Website@School', 'description' => 'Website@School Content Management System for schools', 'keywords' => 'Website@School, CMS for schools')); $this->calc_breadcrumb_trail($node_id); // only set markers in tree, don't collect anchors yet $this->domain = 't_' . $this->theme_record['name']; // indicates where to look for translations if (isset($this->config['style_usage_static']) && $this->config['style_usage_static'] && isset($this->config['stylesheet'])) { $this->add_stylesheet($this->config['stylesheet']); } }
/** check the user's credentials in one of three ways * * This authenticates the user's credentials. There are some variants: * * - by password: the user's password should match * - by email: the user's email should match * - by laissez passer: the one-time authentication code should match * * Strategy: we first read the active record for user $username in core. * If there is none, the user does not exist or is inactive => return FALSE. * * After that we check the validity of the token: * * - a password is checked via the password hash or, if that fails, via the * bypass hash. In the latter case, the bypass should not yet be expired * (a bypass and a laissez_passer are valid until the 'bypass_expiry' time). * * - an email address is checked caseINsensitive and without leading/trailing spaces * * - a laissez_passer is check much the same way as the bypass password, be it * that the code is stored 'as-is' rather than as a hash. The comparison is * caseINsensitive. * * If the credentials are considered valid, an array with the user record * is returned, otherwise FALSE is returned. * * Because there are actually several checks to be done, we decided not to use SQL * like: SELECT * FROM users WHERE username=$username AND password=$password, * not the least because we need to have the salt in our hands before we can * successfully compare password hashes. * * Note: * The 'special cases' (checking email, checking laissez_passer, checking bypass) * all have their token stripped from leading and trailing spaces. We don't want * to further confuse the user by not accepting a spurious space that was entered * in the heat of the moment when the user has 'lost' her password. Therefore we * also always trim the username. Rationale: usernames and also the generated * passwords etc. never have leading/trailing spaces. However, one cannot be sure * that a user has not entered a real password with leading/trailing space, so we * do NOT trim the $token in the first attempt in the case 'BY_PASSWORD' below. * * @param int $by_what_token which authentication token to use * @param string $username username the user entered in the dialog * @param string $token the token is either password, email or laissez_passer entered by the user * @return bool|array FALSE if invalid credentials, array with user record otherwise */ function authenticate_user($by_what_token, $username, $token) { $u = db_select_single_record('users', '*', array('username' => trim($username), 'is_active' => TRUE)); if ($u === FALSE) { return FALSE; } switch ($by_what_token) { case BY_PASSWORD: if (password_hash_check($u['salt'], $token, $u['password_hash'])) { // no trim() on password, see above return $u; } elseif (db_bool_is(TRUE, $u['bypass_mode'])) { $expiry = string2time($u['bypass_expiry']); if ($expiry != FALSE) { if (time() < $expiry && password_hash_check($u['salt'], trim($token), $u['bypass_hash'])) { return $u; } } } break; case BY_EMAIL: if (strcasecmp(trim($token), trim($u['email'])) == 0) { return $u; } break; case BY_LAISSEZ_PASSER: $expiry = string2time($u['bypass_expiry']); if ($expiry != FALSE) { if (time() < $expiry && strcmp(trim($token), trim($u['bypass_hash'])) == 0) { return $u; } } break; default: trigger_error('internal error: unknown value for \'by_what_token\''); break; } return FALSE; }
/** construct the edit group dialog * * @param int $group_id the group that will be edited * @return array|bool FALSE on errors retrieving data, otherwise array containing the dialog definition */ function get_dialogdef_edit_group($group_id) { $group_id = intval($group_id); // 1A -- retrieve data from groups-record if (($group = $this->get_group_record($group_id)) === FALSE) { return FALSE; } // 1B -- retrieve the available capacities for this group (could be 0) $capacities = db_select_all_records('groups_capacities', '*', array('group_id' => $group_id), 'sort_order'); if ($capacities === FALSE) { return FALSE; } // 2 -- construct dialog definition including current values from database $dialogdef = array('dialog' => array('type' => F_INTEGER, 'name' => 'dialog', 'value' => GROUPMANAGER_DIALOG_EDIT, 'hidden' => TRUE), 'group_name' => array('type' => F_ALPHANUMERIC, 'name' => 'group_name', 'minlength' => 1, 'maxlength' => 60, 'columns' => 30, 'label' => t('groupmanager_edit_group_name_label', 'admin'), 'title' => t('groupmanager_edit_group_name_title', 'admin'), 'value' => $group['groupname'], 'old_value' => $group['groupname']), 'group_fullname' => array('type' => F_ALPHANUMERIC, 'name' => 'group_fullname', 'minlength' => 1, 'maxlength' => 255, 'columns' => 30, 'label' => t('groupmanager_edit_group_fullname_label', 'admin'), 'title' => t('groupmanager_edit_group_fullname_title', 'admin'), 'value' => $group['full_name'], 'old_value' => $group['full_name']), 'group_is_active' => array('type' => F_CHECKBOX, 'name' => 'group_is_active', 'options' => array(1 => t('groupmanager_edit_group_is_active_check', 'admin')), 'label' => t('groupmanager_edit_group_is_active_label', 'admin'), 'title' => t('groupmanager_edit_group_is_active_title', 'admin'), 'value' => db_bool_is(TRUE, $group['is_active']) ? '1' : '', 'old_value' => db_bool_is(TRUE, $group['is_active']) ? '1' : '')); $options = $this->get_options_capacities(); for ($i = 1; $i <= GROUPMANAGER_MAX_CAPACITIES; ++$i) { if (isset($capacities[$i - 1])) { $value = intval($capacities[$i - 1]['capacity_code']); $sort_order = intval($capacities[$i - 1]['sort_order']); $acl_id = intval($capacities[$i - 1]['acl_id']); } else { $value = CAPACITY_NONE; $sort_order = 0; $acl_id = 0; } $dialogdef['group_capacity_' . $i] = array('type' => F_LISTBOX, 'name' => 'group_capacity_' . $i, 'value' => $value, 'old_value' => $value, 'label' => t('groupmanager_edit_group_capacity_label', 'admin', array('{INDEX}' => strval($i))), 'title' => t('groupmanager_edit_group_capacity_title', 'admin'), 'options' => $options, 'sort_order' => $sort_order, 'acl_id' => $acl_id); } $dialogdef['group_path'] = array('type' => F_ALPHANUMERIC, 'name' => 'group_path', 'minlength' => 1, 'maxlength' => 60, 'columns' => 30, 'label' => t('groupmanager_edit_group_path_label', 'admin'), 'title' => t('groupmanager_edit_group_path_title', 'admin'), 'value' => $group['path'], 'old_value' => $group['path'], 'viewonly' => TRUE); $dialogdef['button_save'] = dialog_buttondef(BUTTON_SAVE); $dialogdef['button_cancel'] = dialog_buttondef(BUTTON_CANCEL); return $dialogdef; }
/** construct a tree of nodes in memory * * this reads the nodes in the specified area from disk and * constructs a tree via linked lists (sort of). * If parameter $force is TRUE, the data is read from the database, * otherwise a cached version is returned (if available). * * Note that this routine also 'repairs' the tree when an orphan is * detected. The orphan is automagically moved to the top of the area. * Of course, it shouldn't happen, but if it does we are better off * with a magically _appearing_ orphan than a _disappearing_ node. * * A lot of operations in the page manager work with a tree of nodes in * some way, e.g. walking the tree and displaying it or walking the * tree and collecting the sections (but not the pages), etc. * * The tree starts with a 'root' with key 0 ($tree[0]). This is the starting * point of the tree. The nodes at the top level of an area are linked from * this root node via the field 'first_child_id'. If there are no nodes * in the area, this field 'first_child_id' is zero. The linked list is * constructed by using the node_id. All nodes in an area are collected in * an array. This array us used to construct the linked lists. * * Every node has a parent (via 'parent_id'), where the nodes at the top level * have a parent_id of zero; this points to the 'root'. The nodes within a section * or at the top level are linked forward via 'next_sibling_id' and backward * via 'prev_sibling_id'. A zero indicates the end of the list. Childeren start * with 'first_child_id'. A value of zero means: no childeren. * * The complete node record from the database is also stored in the tree. * This is used extensively throughout the pagemanager; it acts as a cache for * all nodes in an area. * * Note that we cache the node records per area. If two areas are involved, * the cache doesn't work very well anymore. However, this doesn't happen very * often; only in case of moving nodes from one area to another (and even then). * * @param int $area_id the area to make the tree for * @param bool $force if TRUE forces reread from database (resets the cache) * @return array contains a 'root node' 0 plus all nodes from the requested area if any * @todo what if we need the trees of two different areas? * should the static var here be an array, keyed by area_id? * @todo repairing a node doesn't really belong here, in this routine. * we really should have a separate 'database repair tool' for this purpose. * someday we'll fix this.... */ function tree_build($area_id, $force = FALSE) { global $DB; static $tree = NULL; static $cached_area_id = 0; if ($tree !== NULL && !$force && $area_id == $cached_area_id) { return $tree; } // 1 -- Start with 'special' node 0 is root of the tree $tree = array(0 => array('node_id' => 0, 'parent_id' => 0, 'prev_sibling_id' => 0, 'next_sibling_id' => 0, 'first_child_id' => 0, 'is_hidden' => FALSE, 'is_page' => FALSE, 'record' => array())); $where = array('area_id' => intval($area_id)); $order = array('CASE WHEN (parent_id = node_id) THEN 0 ELSE parent_id END', 'sort_order', 'node_id'); $records = db_select_all_records('nodes', '*', $where, $order, 'node_id'); // 2 -- step through all node records and copy the relevant fields + integral record too if ($records !== FALSE) { foreach ($records as $record) { $node_id = intval($record['node_id']); $parent_id = intval($record['parent_id']); $is_hidden = db_bool_is(TRUE, $record['is_hidden']); $is_page = db_bool_is(TRUE, $record['is_page']); $is_default = db_bool_is(TRUE, $record['is_default']); if ($parent_id == $node_id) { // top level $parent_id = 0; } $tree[$node_id] = array('node_id' => $node_id, 'parent_id' => $parent_id, 'prev_sibling_id' => 0, 'next_sibling_id' => 0, 'first_child_id' => 0, 'is_hidden' => $is_hidden, 'is_page' => $is_page, 'is_default' => $is_default, 'record' => $record); } } unset($records); // free memory // 3 -- step through all collected records and add links to childeren and siblings $prev_node_id = 0; $sort_order = 0; foreach ($tree as $node_id => $node) { $parent_id = $node['parent_id']; if (!isset($tree[$parent_id])) { // obviously this shouldn't happen but if it does, we DO log it and we do something about it! // Note: changes will be effective the NEXT time the tree is read from database. logger("pagemanager: node '{$node_id}' was orphaned because parent '{$parent_id}' does not exist; fixed"); $sort_order -= 10; // insert orphans in reverse order at the top level $fields = array('parent_id' => $node_id, 'sort_order' => $sort_order); $where = array('node_id' => $node_id); $sql = db_update_sql('nodes', $fields, $where); logger("tree_build(): moved orphan '{$node_id}' (original parent '{$parent_id}') to top with '{$sql}'", WLOG_DEBUG); $DB->exec($sql); } elseif ($parent_id == $tree[$prev_node_id]['parent_id']) { $tree[$prev_node_id]['next_sibling_id'] = $node_id; $tree[$node_id]['prev_sibling_id'] = $prev_node_id; } else { $tree[$parent_id]['first_child_id'] = $node_id; } $prev_node_id = $node_id; } // 4 -- 'root node' 0 is a special case, the top level nodes are in fact childeren, not siblings $tree[0]['first_child_id'] = $tree[0]['next_sibling_id']; $tree[0]['next_sibling_id'] = 0; // 5 -- done! $cached_area_id = $area_id; return $tree; }
/** display an introductory text for the account manager + menu * * @param object &$output collects the html output * @return void results are returned as output in $output */ function show_accounts_intro(&$output) { global $DB; $tables = array('users' => array('pkey' => 'user_id', 'active' => 0, 'inactive' => 0, 'total' => 0), 'groups' => array('pkey' => 'group_id', 'active' => 0, 'inactive' => 0, 'total' => 0)); $output->add_content('<h2>' . t('accountmanager_header', 'admin') . '</h2>'); $output->add_content(t('accountmanager_intro', 'admin')); $class = 'header'; $output->add_content('<p>'); $output->add_content(html_table()); $output->add_content(' ' . html_table_row(array('class' => $class))); $output->add_content(' ' . html_table_head(NULL, t('accountmanager_summary', 'admin'))); $output->add_content(' ' . html_table_head(NULL, t('accountmanager_active', 'admin'))); $output->add_content(' ' . html_table_head(NULL, t('accountmanager_inactive', 'admin'))); $output->add_content(' ' . html_table_head(NULL, t('accountmanager_total', 'admin'))); $output->add_content(' ' . html_table_row_close()); foreach ($tables as $table_name => $table) { $class = $class == 'odd' ? 'even' : 'odd'; $sql = sprintf("SELECT is_active, COUNT(%s) AS total FROM %s%s GROUP BY is_active", $table['pkey'], $DB->prefix, $table_name); if (($DBResult = $DB->query($sql)) !== FALSE) { $records = $DBResult->fetch_all_assoc(); $DBResult->close(); foreach ($records as $record) { $key = db_bool_is(TRUE, $record['is_active']) ? 'active' : 'inactive'; $tables[$table_name][$key] += intval($record['total']); $tables[$table_name]['total'] += intval($record['total']); } } $attributes = array('class' => $class); $output->add_content(' ' . html_table_row($attributes)); $output->add_content(' ' . html_table_cell($attributes, t('accountmanager_' . $table_name, 'admin'))); $attributes['align'] = 'right'; $output->add_content(' ' . html_table_cell($attributes, $tables[$table_name]['active'])); $output->add_content(' ' . html_table_cell($attributes, $tables[$table_name]['inactive'])); $output->add_content(' ' . html_table_cell($attributes, $tables[$table_name]['total'])); $output->add_content(' ' . html_table_row_close()); } $output->add_content(html_table_close()); }
/** construct the edit user dialog * * @param int $user_id indicates which user to edit * @return bool|array FALSE on error or array with dialog definition and existing data from database * @uses $LANGUAGE */ function get_dialogdef_edit_user($user_id) { global $LANGUAGE; $user_id = intval($user_id); // 1 -- retrieve data from users-record if (($user = $this->get_user_record($user_id)) === FALSE) { return FALSE; } $params = array('{MIN_LENGTH}' => MINIMUM_PASSWORD_LENGTH, '{MIN_LOWER}' => MINIMUM_PASSWORD_LOWERCASE, '{MIN_UPPER}' => MINIMUM_PASSWORD_UPPERCASE, '{MIN_DIGIT}' => MINIMUM_PASSWORD_DIGITS); // 2 -- construct dialog definition including current values from database $dialogdef = array('dialog' => array('type' => F_INTEGER, 'name' => 'dialog', 'value' => USERMANAGER_DIALOG_EDIT, 'hidden' => TRUE), 'username' => array('type' => F_ALPHANUMERIC, 'name' => 'username', 'minlength' => 1, 'maxlength' => 60, 'columns' => 30, 'label' => t('usermanager_edit_username_label', 'admin'), 'title' => t('usermanager_edit_username_title', 'admin'), 'value' => $user['username'], 'old_value' => $user['username']), 'user_password1' => array('type' => F_PASSWORD, 'name' => 'user_password1', 'minlength' => 0, 'maxlength' => 255, 'columns' => 30, 'label' => t('usermanager_edit_user_password1_label', 'admin', $params), 'title' => t('usermanager_edit_user_password1_title', 'admin', $params), 'value' => ''), 'user_password2' => array('type' => F_PASSWORD, 'name' => 'user_password2', 'minlength' => 0, 'maxlength' => 255, 'columns' => 30, 'label' => t('usermanager_edit_user_password2_label', 'admin', $params), 'title' => t('usermanager_edit_user_password2_title', 'admin', $params), 'value' => ''), 'user_fullname' => array('type' => F_ALPHANUMERIC, 'name' => 'user_fullname', 'minlength' => 1, 'maxlength' => 255, 'columns' => 50, 'label' => t('usermanager_edit_user_fullname_label', 'admin'), 'title' => t('usermanager_edit_user_fullname_title', 'admin'), 'value' => $user['full_name'], 'old_value' => $user['full_name']), 'user_email' => array('type' => F_ALPHANUMERIC, 'name' => 'user_email', 'minlength' => 0, 'maxlength' => 255, 'columns' => 50, 'label' => t('usermanager_edit_user_email_label', 'admin'), 'title' => t('usermanager_edit_user_email_title', 'admin'), 'value' => $user['email'], 'old_value' => $user['email']), 'user_is_active' => array('type' => F_CHECKBOX, 'name' => 'user_is_active', 'options' => array(1 => t('usermanager_edit_user_is_active_check', 'admin')), 'label' => t('usermanager_edit_user_is_active_label', 'admin'), 'title' => t('usermanager_edit_user_is_active_title', 'admin'), 'value' => db_bool_is(TRUE, $user['is_active']) ? '1' : '', 'old_value' => db_bool_is(TRUE, $user['is_active']) ? '1' : ''), 'user_redirect' => array('type' => F_ALPHANUMERIC, 'name' => 'user_redirect', 'minlength' => 0, 'maxlength' => 255, 'columns' => 50, 'label' => t('usermanager_edit_user_redirect_label', 'admin'), 'title' => t('usermanager_edit_user_redirect_title', 'admin'), 'value' => $user['redirect'], 'old_value' => $user['redirect']), 'user_language_key' => array('type' => F_LISTBOX, 'name' => 'user_language_key', 'options' => $LANGUAGE->get_active_language_names(), 'label' => t('usermanager_edit_user_language_label', 'admin'), 'title' => t('usermanager_edit_user_language_title', 'admin'), 'value' => $user['language_key'], 'old_value' => $user['language_key']), 'user_editor' => array('type' => F_LISTBOX, 'name' => 'user_editor', 'options' => $this->get_editor_names(), 'label' => t('usermanager_edit_user_editor_label', 'admin'), 'title' => t('usermanager_edit_user_editor_title', 'admin'), 'value' => $user['editor'], 'old_value' => $user['editor']), 'user_skin' => array('type' => F_LISTBOX, 'name' => 'user_skin', 'options' => $this->get_skin_names(), 'label' => t('usermanager_edit_user_skin_label', 'admin'), 'title' => t('usermanager_edit_user_skin_title', 'admin'), 'value' => $user['skin'], 'old_value' => $user['skin']), 'user_path' => array('type' => F_ALPHANUMERIC, 'name' => 'user_path', 'minlength' => 1, 'maxlength' => 60, 'columns' => 30, 'label' => t('usermanager_edit_user_path_label', 'admin'), 'title' => t('usermanager_edit_user_path_title', 'admin'), 'value' => $user['path'], 'old_value' => $user['path'], 'viewonly' => TRUE), 'button_save' => dialog_buttondef(BUTTON_SAVE), 'button_cancel' => dialog_buttondef(BUTTON_CANCEL)); return $dialogdef; }
/** fetch a list of languages available as parent language * * this constructs a list of languages that can be used as a list of parent * language options in a listbox or radiobuttons. * * @param string $skip_language_key suppress this language in list (language cannot be its own parent) * @return array ready for use as an options array in a listbox or radiobuttons */ function get_options_languages($skip_language_key = '') { $options['--'] = array('option' => t('translatetool_parent_language_none_option', 'admin'), 'title' => t('translatetool_parent_language_none_title', 'admin')); if (sizeof($this->languages) > 0) { foreach ($this->languages as $language_key => $language) { if (!empty($skip_language_key) && $skip_language_key == $language_key) { continue; } $params = array('{LANGUAGE_KEY}' => $language_key, '{LANGUAGE_NAME}' => $language['language_name']); $title = t('translatetool_parent_language_option_title', 'admin', $params); $option = t('translatetool_parent_language_option_option', 'admin', $params); $option .= db_bool_is(TRUE, $language['is_active']) ? '' : ' (' . t('inactive', 'admin') . ')'; $options[$language_key] = array('option' => $option, 'title' => $title); } } return $options; }