/** install the theme * * this routine performs the necessary actions to make this theme usable. * More specific, this routine adds a handfull of default values into the * themes_properties table. Once a theme is actually used in an area, these * defaults are copied from the themes_properties table to the * themes_areas_properties table for the selected area. The user can subsequently * edit these properties in the Area Manager. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @return bool TRUE on success + output via $messages, FALSE otherwise */ function frugal_install(&$messages, $theme_id) { $now = strftime('%Y-%m-%d %T'); $properties = array(array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'quicktop_section_id', 'type' => 'i', 'value' => '0', 'sort_order' => 10, 'extra' => 'minvalue=0', 'description' => 'indicates which section to use for the quicklinks at the top of the page')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'quickbottom_section_id', 'type' => 'i', 'value' => '0', 'sort_order' => 20, 'extra' => 'minvalue=0', 'description' => 'indicates which section to use for the quicklinks at the bottom of the page')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_image', 'type' => 's', 'value' => 'program/graphics/waslogo-284x71.png', 'sort_order' => 30, 'extra' => 'maxlength=255', 'description' => 'the URL of the logo file or a path relative to the directory holding index.php')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_width', 'type' => 'i', 'value' => '284', 'sort_order' => 40, 'extra' => 'minvalue=0;maxvalue=2048', 'description' => 'the width of the logo in pixels')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'logo_height', 'type' => 'i', 'value' => '71', 'sort_order' => 50, 'extra' => 'minvalue=0;maxvalue=1536', 'description' => 'the height of the logo in pixels')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'show_breadcrumb_trail', 'type' => 'b', 'value' => '1', 'sort_order' => 60, 'description' => 'this enables/disables the display of the breadcrumb trail in the navigation')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_static', 'type' => 'b', 'value' => '1', 'sort_order' => 70, 'extra' => '', 'description' => 'if TRUE this includes the static stylesheet')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'stylesheet', 'type' => 's', 'value' => 'program/styles/base.css', 'sort_order' => 80, 'extra' => 'maxlength=255', 'description' => 'the URL of the stylesheet or a path relative to the directory holding index.php')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_area', 'type' => 'b', 'value' => '1', 'sort_order' => 90, 'extra' => '', 'description' => 'if TRUE this includes the additional style information')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style', 'type' => 's', 'value' => "/* Demo of Bazaar Style Style sheets */\n" . "#content h1 {\n" . " background-color: #FF33FF;\n" . "}\n", 'sort_order' => 100, 'extra' => 'maxlength=65535;rows=10;columns=70', 'description' => 'additional style information that will be processed AFTER the static stylesheet file')), array('table' => 'themes_properties', 'fields' => array('theme_id' => $theme_id, 'name' => 'style_usage_node', 'type' => 'b', 'value' => '1', 'sort_order' => 110, 'extra' => '', 'description' => 'if TRUE this allows for addition style information from individual sections/pages'))); $retval = TRUE; // assume success foreach ($properties as $property) { if (db_insert_into($property['table'], $property['fields']) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** install the module * * this routine installs the module. For this module there * are a few properties that need to be stored in the main * modules_properties table. The specific table for this module is * already created based on the tabledefs); see install/crew_tabledefs.php. * * Note that the record for this module is already created in the * modules table; the pkey is $module_id. * * @param array &$messages collects the (error) messages * @param int $module_id the key for this module in the modules table * @return bool TRUE on success + output via $messages, FALSE otherwise */ function crew_install(&$messages, $module_id) { $properties = array('origin' => array('type' => 's', 'value' => isset($_SERVER['HTTP_HOST']) ? 'http://' . $_SERVER['HTTP_HOST'] : '', 'extra' => 'maxlength=255', 'description' => 'this must match the origin as seen by the browser of the CREW-user'), 'location' => array('type' => 's', 'value' => '', 'extra' => 'maxlength=255', 'description' => 'this is the location (URL) of the websocket server'), 'secret' => array('type' => 's', 'value' => '', 'extra' => 'maxlength=255', 'description' => 'this shared secret is necessary to access the websocket server')); $retval = TRUE; // assume success $table = 'modules_properties'; $sort_order = 0; foreach ($properties as $name => $property) { $property['module_id'] = $module_id; $property['name'] = $name; $sort_order += 10; $property['sort_order'] = $sort_order; if (db_insert_into($table, $property) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** attempt to lock all node records in a subtree * * this recursively walks the subtree starting at $node_id and attempts to * - lock every node in the subtree, AND * - write the new area_id in an auxiliary field of every node in the subtree * * With at least two trips to the database (at least one for the lock and * another one for writing the auxiliary field) per node, this is an expensive * routine. Maybe it is possible to combine locking and writing the auxiliary * field. However, in order to keep things readable I decided against that. * * This routine returns FALSE if any of the nodes in the subtree could NOT be * locked. If each and every node in the subtree is successfully locked, TRUE is * returned. * * Note that all these locks are reset/released the moment the actual move is * done, by resetting both the locked_by field and the area_id field. That may * hurt readability too, but less than combining lock + setting auxiliary field. * See {@link save_node_new_area_mass_move()} for more information. * * @param int $node_id the node which we are going to move to $new_area_id * @param int $new_area_id the area to which we want to move the subtree $node_id * @return bool FALSE on error, TRUE on success * @uses lock_records_subtree() */ function lock_records_subtree($node_id, $new_area_id) { static $level = 0; $lockinfo = array(); while ($node_id != 0) { $is_page = $this->tree[$node_id]['is_page']; if (!lock_record_node($node_id, $lockinfo)) { $msg = message_from_lockinfo($lockinfo, $node_id, $is_page); $this->output->add_message($msg); logger(__FUNCTION__ . "(): cannot lock node {$node_id} in subtree: {$msg}", WLOG_DEBUG); return FALSE; } elseif (db_update('nodes', array('auxiliary' => $new_area_id), array('node_id' => $node_id)) === FALSE) { logger(__FUNCTION__ . "(): cannot write new area_id {$new_area_id} to auxiliary field in node {$node_id}: " . db_errormessage(), WLOG_DEBUG); return FALSE; } if (!$is_page && $this->tree[$node_id]['first_child_id'] != 0) { if ($level >= MAXIMUM_ITERATIONS) { $this->output->add_message(t('too_many_levels', 'admin', array('{NODE}' => strval($node_id)))); logger(__FUNCTION__ . '(): too many levels in node ' . $node_id, WLOG_DEBUG); return FALSE; } else { ++$level; $retval = $this->lock_records_subtree($this->tree[$node_id]['first_child_id'], $new_area_id); --$level; if ($retval === FALSE) { return FALSE; } } } $node_id = $this->tree[$node_id]['next_sibling_id']; } return TRUE; }
/** retrieve the records of the groups of which user $user_id is a member * * @param int $user_id the user we're looking at * @return array 0, 1 or more acl_id => $group_record pairs * @uses $DB */ function get_user_groups($user_id) { global $DB; $records = array(); $sql = sprintf("SELECT g.* " . "FROM %sgroups g " . "INNER JOIN %susers_groups_capacities ugc " . "USING (group_id) " . "WHERE ugc.capacity_code <> 0 AND ugc.user_id = %d " . "ORDER BY g.groupname", $DB->prefix, $DB->prefix, $user_id); if (($DBResult = $DB->query($sql)) !== FALSE) { $records = $DBResult->fetch_all_assoc('group_id'); $DBResult->close(); } else { logger(sprintf("%s(): cannot retrieve groups for user '%d': %s", __FUNCTION__, $user_id, db_errormessage())); } return $records; }
/** retrieve the current version of the document + other workshop data * * @param int $node_id which one are we looking at? * @return bool|array FALSE on error, array with record from db otherwise */ function crew_view_get_workshop_data($node_id) { global $DB; $sql = sprintf('SELECT w.*, u.username, u.full_name ' . 'FROM %sworkshops w LEFT JOIN %susers u ON w.muser_id = u.user_id ' . 'WHERE node_id = %d', $DB->prefix, $DB->prefix, $node_id); if (($db_result = $DB->query($sql, 1)) === FALSE || $db_result->num_rows != 1) { logger(sprintf('%s(): workshop %d data error: %s', __FUNCTION__, $node_id, db_errormessage())); return FALSE; } $record = $db_result->fetch_row_assoc(); $db_result->close(); return $record; }
/** add demonstration data to the system * * this routine adds demonstration data to the freshly installed system * * Note * If the theme is installed via the Install Wizard, this routine is * called. However, if a theme is installed as an additional theme * after installation, the {$theme}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['title'] => the name of the site (as entered by Wilhelmina Bladergroen) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * $config['demo_string'] => array with demo strings from /program/install/languages/LL/demodata.php * $config['demo_replace'] => array with search/replace pairs to 'jazz up' the demo strings * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @param array $config pertinent data for the new website + demodata foundation * @param array $manifest a copy from the manifest for this theme * @return bool TRUE on success + output via $messages, FALSE otherwise */ function sophia_demodata(&$messages, $theme_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 1A -- prepare for setting up demo settings $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']); $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']); $progwww = $config['progwww']; $slogan = $config['demo_string']['welcome_title']; $area_id = intval($config['demo_areas']['public']['area_id']); $theme_id = intval($theme_id); $theme_name = $manifest['name']; $aboutus = $config['demo_string']['aboutus_content']; $email = $config['replyto']; // 1B -- actually construct settings $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'style' => sprintf("#navigation ul li { background-image: url('%s/themes/%s/stencil0.png'); }\n" . "#navigation ul li.navigation_button5 { background-color: #FF3399; }\n", $progwww, $theme_name), 'header_text' => $slogan, 'left_top_html' => sprintf("<img src=\"%s/themes/%s/calendula.jpg\" width=\"120\" height=\"90\" alt=\"\">\n", $progwww, $theme_name), 'left_bottom_html' => sprintf("<div style=\"margin-bottom: 30px;\">\n%s\n</div>\n", $aboutus), 'footer_text' => sprintf('<b><a href="mailto:%s">%s</a></b>', $email, $email)); // 2A -- start with the default settings (copy from theme_properties) $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id); if ($DB->exec($sql) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } // 2B -- update/overwrite the default settings with our own demo-data for area $area_id foreach ($settings as $name => $value) { $fields = array('value' => strval($value)); $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name)); if (db_update('themes_areas_properties', $fields, $where) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** retrieve a list of modules that should appear in the module manager * * this routine returns an array with id, name, title and * description of all active modules that have at least * one parameter in the modules_properties table. * If there are no modules available (or an error occurs) * an empty array is returned. The modules in the list is ordered * by the translated name (title) of the module, i.e. the order * depends on the current translation language. * * @param bool $forced if TRUE a fresh trip to the database is forced * @return array list of modules sorted by (translated) title */ function modulemanager_get_modules($forced = FALSE) { global $DB; static $modules = NULL; if ($modules === NULL || $forced) { $sql = sprintf('SELECT DISTINCT m.module_id,m.name ' . 'FROM %smodules m ' . 'INNER JOIN %smodules_properties mp USING(module_id) ' . 'WHERE (is_active)', $DB->prefix, $DB->prefix); if (($result = $DB->query($sql)) === FALSE) { logger('modulemanager: ' . db_errormessage()); return array(); } $records = $result->fetch_all_assoc('module_id'); $result->close(); // we now have an array with id's and (short) names keyed by id. // now pickup translated names foreach ($records as $module_id => $module) { $name = $module['name']; $records[$module_id]['title'] = t('title', 'm_' . $name); $records[$module_id]['description'] = t('description', 'm_' . $name); } uasort($records, 'modulemanager_cmp'); $modules = $records; } return $modules; }
/** save the modified content data of this module linked to node $node_id * * this validates and saves the data that was submitted by the user. * If validation fails, or storing the data doesn't work, the flag $edit_again * is set to TRUE and the return value is FALSE. * * If the user has cancelled the operation, the flag $edit_again is set to FALSE * and the return value is also FALSE. * * If the modified data is stored successfully, the return value is TRUE (and * the value of $edit_again is a don't care). * * Here is a summary of return values. * * - retval = TRUE ==> data saved successfully * - retval = FALSE && edit_again = TRUE ==> re-edit the data, show the edit dialog again * - retval = FALSE && edit_again = FALSE ==> cancelled, do nothing * * @param object &$output collects the html output (if any) * @param int $area_id the area in which $node_id resides * @param int $node_id the node to which the content is connected * @param array $module the module record straight from the database * @param bool $viewonly if TRUE, editing and hence saving is not allowed * @param bool &$edit_again set to TRUE if we need to edit the content again, FALSE otherwise * @return bool TRUE on success + output stored via $output, FALSE otherwise */ function snapshots_save(&$output, $area_id, $node_id, $module, $viewonly, &$edit_again) { global $USER; // 1 -- bail out if cancelled or viewonly if (isset($_POST['button_cancel']) || $viewonly) { $edit_again = FALSE; return FALSE; } // 2 -- redo if invalid data was submitted $invalid = FALSE; $dialogdef = snapshots_get_dialogdef($viewonly); if (!dialog_validate($dialogdef)) { $invalid = TRUE; } if (!snapshots_check_path($dialogdef['snapshots_path'], $area_id, $node_id)) { $invalid = TRUE; } if (isset($dialogdef['snapshots_path']['warnings']) && $dialogdef['snapshots_path']['warnings'] > 0) { $output->add_message($dialogdef['snapshots_path']['warning_messages']); } // show errors to the user and redo if ($invalid) { foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $output->add_message($item['error_messages']); } } $edit_again = TRUE; return FALSE; } // 3 -- actually save the new setting $now = strftime('%Y-%m-%d %T'); $table = 'snapshots'; $fields = array('header' => $dialogdef['header']['value'], 'introduction' => $dialogdef['introduction']['value'], 'snapshots_path' => $dialogdef['snapshots_path']['value'], 'variant' => $dialogdef['variant']['value'], 'dimension' => intval($dialogdef['dimension']['value']), 'mtime' => $now, 'muser_id' => $USER->user_id); $where = array('node_id' => intval($node_id)); if (db_update($table, $fields, $where) === FALSE) { logger(sprintf('%s(): error saving config value: %s', __FUNCTION__, db_errormessage())); $edit_again = TRUE; return FALSE; } else { return TRUE; // $edit_again is a don't care } }
/** perform actual update to version 2012041900 * * Changes between 2011093000 and 2012041900: * - addition of the ckeditor-option in the site configuration table * * @param object &$output collects the html output * @return bool TRUE on success, FALSE otherwise */ function update_core_2012041900(&$output) { global $CFG, $DB; $version = 2012041900; if ($CFG->version >= $version) { return TRUE; } // // 1 -- maybe change default editor to CKEditor // $table = 'config'; $fields = array('extra' => 'options=ckeditor,fckeditor,plain', 'description' => 'Default rich text editor - USER-defined, default ckeditor'); $where = array('name' => 'editor'); if (!isset($CFG->editor) || $CFG->editor == 'fckeditor') { $fields['value'] = 'ckeditor'; } if (db_update($table, $fields, $where) === FALSE) { $msg = sprintf("%s(): cannot update editor configuration: %s", __FUNCTION__, db_errormessage()); logger($msg); $output->add_message(htmlspecialchars($msg)); $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version)))); return FALSE; } // // 2 -- maybe add some additional fields to nodes, users // $addfielddefs = array('nodes:style' => array('name' => 'style', 'type' => 'text', 'notnull' => TRUE, 'comment' => 'additional style information to add AFTER static and area-level style'), 'users:skin' => array('name' => 'skin', 'type' => 'varchar', 'length' => 20, 'notnull' => TRUE, 'default' => 'base', 'comment' => 'preferred skin')); foreach ($addfielddefs as $table_field => $fielddef) { list($table, $field) = explode(':', $table_field); if (($DBResult = $DB->query(db_select_sql($table, $field), 1)) !== FALSE) { $DBResult->close(); logger(sprintf("%s(): field '%s' already exists in '%s', skipping ALTER TABLE", __FUNCTION__, $field, $table)); } else { $sql = sprintf('ALTER TABLE %s%s ADD COLUMN (%s)', $DB->prefix, $table, $DB->column_definition($fielddef)); if (($retval = $DB->exec($sql)) === FALSE) { $msg = sprintf("%s(): cannot add field '%s' to table '%s': %s", __FUNCTION__, $field, $table, db_errormessage()); logger($msg); $output->add_message(htmlspecialchars($msg)); $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version)))); return FALSE; } else { logger(sprintf("%s(): success adding field '%s' to table '%s'", __FUNCTION__, $field, $table)); } } } // // 3 -- maybe get rid of old field 'high_visibility' // if (($DBResult = $DB->query(db_select_sql('users', 'high_visibility'), 1)) === FALSE) { logger(sprintf("%s(): field 'high_visibility' no longer exists in 'users', skipping ALTER TABLE", __FUNCTION__)); } else { $DBResult->close(); $changes = array('base' => FALSE, 'textonly' => TRUE); foreach ($changes as $newval => $oldval) { if (($retval = db_update('users', array('skin' => $newval), array('high_visibility' => $oldval))) === FALSE) { $msg = sprintf("%s(): cannot update field 'users.skin' to '%s': %s", __FUNCTION__, $newval, db_errormessage()); logger($msg); $output->add_message(htmlspecialchars($msg)); $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version)))); return FALSE; } else { logger(sprintf("%s(): success setting 'users.skin' to '%s' in %d record(s)", __FUNCTION__, $newval, $retval)); } } $sql = sprintf('ALTER TABLE %susers DROP COLUMN high_visibility', $DB->prefix); if (($retval = $DB->exec($sql)) === FALSE) { $msg = sprintf("%s(): cannot drop field 'high_visibility' from table 'users': %s", __FUNCTION__, db_errormessage()); logger($msg); $output->add_message(htmlspecialchars($msg)); $output->add_message(t('update_core_error', 'admin', array('{VERSION}' => strval($version)))); return FALSE; } else { logger(sprintf("%s(): success dropping field 'high_visibility' from table 'users'", __FUNCTION__)); } } // // 4 -- If all is well, we update the version number in the database AND in $CFG->version // return update_core_version($output, $version); }
/** determine the number of existing properties for a theme in an area * * @param int $area_id * @param int $theme_id * @return int number of existing properties */ function count_existing_theme_properties($area_id, $theme_id) { $where = array('area_id' => intval($area_id), 'theme_id' => intval($theme_id)); $record = db_select_single_record('themes_areas_properties', 'count(*) as properties', $where); if ($record === FALSE) { logger("areamanager: error counting properties in theme '{$theme_id} and area '{$area_id}': " . db_errormessage()); $num = 0; } else { $num = intval($record['properties']); } return $num; }
/** retrieve page data for htmlpage module on a node * * this retrieves data from the page $node_id (requires knowledge of * internals of htmlpage module/table) in order to show that in a box * in the 3rd column. * The content is wrapped in a div which has a unique ID of the form * sidebar_blockN where N counts from 1 upward and a common class * sidebar_htmlpage. This allows for connecting style information to * a particular sidebar block in a flexible way. * * @param in $index block number (1-based) * @param int $node_id identifies the pagedata to retrieve * @param string $m increased readbility * @return string ready-to-use HTML-code */ function cornelia_get_sidebar_htmlpage($index, $node_id, $m = '') { $attributes = array('id' => 'sidebar_block' . strval($index), 'class' => 'sidebar_htmlpage'); $s = $m . html_tag('div', $attributes) . "\n"; // fetch actual content from database (requires knowledge of internals of htmlpage module/table) $table = 'htmlpages'; $node_id = intval($node_id); $where = array('node_id' => $node_id); $fields = array('page_data'); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s: no pagedata (node=%d): %s', __FUNCTION__, $node_id, db_errormessage())); } else { $s .= $record['page_data'] . "\n"; } $s .= $m . "</div>\n"; return $s; }
/** retrieve acl-data from table into a sparse array * * @param string $table name of the table which holds the acls * @return array zero or more elements with permissions */ function fetch_acls_from_table($table) { $where = $this->where_acl_id(); $a = array(); switch ($table) { case 'acls_areas': $fields = array('permissions_intranet', 'permissions_modules', 'permissions_nodes'); $keys = array('area_id'); break; case 'acls_nodes': $fields = array('permissions_modules', 'permissions_nodes'); $keys = array('node_id'); break; case 'acls_modules': $fields = array('permissions_modules'); $keys = array('module_id'); break; case 'acls_modules_areas': $fields = array('permissions_modules'); $keys = array('module_id', 'area_id'); break; case 'acls_modules_nodes': $fields = array('permissions_modules'); $keys = array('module_id', 'node_id'); break; default: logger(sprintf("%s(): unknown table '%s'; cannot retrieve acls", __FUNCTION__, $table)); return array(); // empty array equates to: no access break; } $records = db_select_all_records($table, '*', $where); if ($records === FALSE) { logger(sprintf("%s(): cannot get acls from '%s'; %s'", __FUNCTION__, $table, db_errormessage())); return array(); // empty array equates to: no access } if (sizeof($keys) == 1) { $key = $keys[0]; if (sizeof($fields) > 1) { // acls_areas, acls_nodes foreach ($records as $record) { $k = intval($record[$key]); foreach ($fields as $f) { if (($v = intval($record[$f])) != 0) { $a[$k][$f] = isset($a[$k][$f]) ? $a[$k][$f] | $v : $v; } } } } else { // acls_modules $field = $fields[0]; foreach ($records as $record) { $k = intval($record[$key]); if (($v = intval($record[$field])) != 0) { $a[$k] = isset($a[$k]) ? $a[$k] | $v : $v; } } } } else { // acls_modules_areas, acls_modules_nodes $field = $fields[0]; foreach ($records as $record) { if (($v = intval($record[$field])) != 0) { $k0 = intval($record[$keys[0]]); $k1 = intval($record[$keys[1]]); $a[$k0][$k1] = isset($a[$k0][$k1]) ? $a[$k0][$k1] | $v : $v; } } } unset($records); return $a; }
/** save the modified content data of this module linked to node $node_id * * this validates and saves the data that was submitted by the user. * If validation fails, or storing the data doesn't work, the flag $edit_again * is set to TRUE and the return value is FALSE. * * If the user has cancelled the operation, the flag $edit_again is set to FALSE * and the return value is also FALSE. * * If the modified data is stored successfully, the return value is TRUE (and * the value of $edit_again is a don't care). * * Here is a summary of return values. * * - retval = TRUE ==> data saved successfully * - retval = FALSE && edit_again = TRUE ==> re-edit the data, show the edit dialog again * - retval = FALSE && edit_again = FALSE ==> cancelled, do nothing * * @param object &$output collects the html output (if any) * @param int $area_id the area in which $node_id resides * @param int $node_id the node to which the content is connected * @param array $module the module record straight from the database * @param bool $viewonly if TRUE, editing and hence saving is not allowed * @param bool &$edit_again set to TRUE if we need to edit the content again, FALSE otherwise * @return bool TRUE on success + output stored via $output, FALSE otherwise */ function redirect_save(&$output, $area_id, $node_id, $module, $viewonly, &$edit_again) { global $USER; // 1 -- bail out if cancelled or viewonly if (isset($_POST['button_cancel']) || $viewonly) { $edit_again = FALSE; return FALSE; } // 2 -- redo if invalid data was submitted $dialogdef = redirect_get_dialogdef($viewonly); if (!dialog_validate($dialogdef)) { // there were errors, show them to the user and do it again foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $output->add_message($item['error_messages']); } } $edit_again = TRUE; return FALSE; } // 3 -- actually save the new setting $now = strftime('%Y-%m-%d %T'); $table = 'nodes'; $fields = array('link_href' => trim($dialogdef['link_href']['value']), 'link_target' => trim($dialogdef['link_target']['value']), 'mtime' => $now); $where = array('node_id' => intval($node_id)); $retval = db_update($table, $fields, $where); if (db_update($table, $fields, $where) === FALSE) { logger(sprintf('%s(): error saving config value: %s', __FUNCTION__, db_errormessage())); $edit_again = TRUE; return FALSE; } else { return TRUE; // $edit_again is a don't care } }
/** retrieve current list of addresses in an array (could be empty) * * this retrieves the addresses associated with $node_id from the * database. As an important side effect all entries' sort order values * are renumbered. This means that we always have a neat set of sort * order numbers 10, 20, ... * * On error we return an empty array as a sort of best effort. * The error is logged though. * * @param int $node_id indicates page * @return array records from the database with sort order renumbered OR an empty array */ function mailpage_get_addresses($node_id) { $table = 'mailpages_addresses'; $keyfield = 'mailpage_address_id'; $fields = '*'; $where = array('node_id' => intval($node_id)); $order = array('sort_order', $keyfield); if (($records = db_select_all_records($table, $fields, $where, $order, $keyfield)) === FALSE) { logger(sprintf('%s(): error retrieving addresses: %s', __FUNCTION__, db_errormessage())); return array(); } // side-effect: renumber the sort order of the addresses if not a nice list of 10, 20, ... $sort_order = 0; foreach ($records as $k => $record) { $sort_order += 10; if ($record['sort_order'] == $sort_order) { continue; } $records[$k]['sort_order'] = $sort_order; $where = array($keyfield => intval($record[$keyfield])); $fields = array('sort_order' => $sort_order); if (db_update($table, $fields, $where) === FALSE) { logger(sprintf('%s(): error renumbering addresses: %s', __FUNCTION__, db_errormessage())); } } return $records; }
/** create a few alerts * * * @param array &$messages used to return (error) messages to caller * @param array &$config pertinent information about the site * @param array &$tr translations of demodata texts * @return bool TRUE on success + data entered into database, FALSE on error */ function demodata_alerts(&$messages, &$config, &$tr) { $retval = TRUE; $now = strftime("%Y-%m-%d %T"); $email = $config['user_email']; $alerts = array('webmaster' => array('full_name' => $config['user_full_name'], 'email' => $email, 'cron_interval' => 1440, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_1440_minutes'] . "\n" . $tr['alerts_all_areas'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (" . $config['user_full_name'] . ")\n", 'is_active' => TRUE), 'acackl' => array('full_name' => 'Amelia Cackle', 'email' => $email, 'cron_interval' => 60, 'cron_next' => $now, 'messages' => 1, 'message_buffer' => $now . "\n" . $tr['alerts_initial_load'] . "\n" . $tr['alerts_every_60_minutes'] . "\n" . $tr['alerts_private_area'] . "\n" . $tr['alerts_email_address'] . "\n" . $email . " (Amelia Cackle)\n", 'is_active' => TRUE)); foreach ($alerts as $alert => $fields) { if (($alert_id = db_insert_into_and_get_id('alerts', $fields, 'alert_id')) === FALSE) { $messages[] = $tr['error'] . ' ' . db_errormessage(); $retval = FALSE; } $alerts[$alert]['alert_id'] = intval($alert_id); } $alerts_areas_nodes = array('webmaster' => array('alert_id' => $alerts['webmaster']['alert_id'], 'area_id' => 0, 'node_id' => 0, 'flag' => TRUE), 'acackl' => array('alert_id' => $alerts['acackl']['alert_id'], 'area_id' => $config['demo_areas']['private']['area_id'], 'node_id' => 0, 'flag' => TRUE)); foreach ($alerts_areas_nodes as $fields) { if (db_insert_into('alerts_areas_nodes', $fields) === FALSE) { $messages[] = $tr['error'] . ' ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** 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']); } }
/** retrieve a single group's record possibly from the cache * * @param int $group_id identifies the group record * @param bool $forced if TRUE unconditionally fetch the record from the database * @return bool|array FALSE if there were errors, the group record otherwise */ function get_group_record($group_id, $forced = FALSE) { $group_id = intval($group_id); if (!isset($this->groups[$group_id]) || $forced) { $table = 'groups'; $fields = '*'; $where = array('group_id' => $group_id); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf("%s.%s(): cannot retrieve record for group '%d': %s", __CLASS__, __FUNCTION__, $group_id, db_errormessage())); $this->output->add_message(t('error_retrieving_data', 'admin')); return FALSE; } else { $this->groups[$group_id] = $record; } } return isset($this->groups[$group_id]) ? $this->groups[$group_id] : FALSE; }
/** add demonstration data to the system * * this routine adds to the existing set of demonstration data as specified * in $config. Here we add a few nodes as follows: * * 'snapshots0': a section containing one page connected to the snapshots_module * 'snapshots1': a page in section 'snapshots0' acting as an example set of snapshots * * The section 'snapshots0' is added at the bottom of the demo-section 'news' * Maybe not the best place, but at least we don't add yet another top level * menu item. * * Note * If the module is installed via the Install Wizard, this routine is * called. However, if a module is installed as an additional module * after installation, the {$module}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * $config['demo_string'] => array with demo strings from /program/install/languages/LL/demodata.php * $config['demo_replace'] => array with search/replace pairs to 'jazz up' the demo strings * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. Note that we add our own additions to the array * $config so other modules and themes can determine the correct status quo w.r.t. the * demodata nodes etc. * * @param array &$messages collects the (error) messages * @param int $module_id the key for this module in the modules table * @param array $configuration pertinent data for the new website + demodata foundation * @param array $manifest a copy of the manifest for this module * @return bool TRUE on success + output via $messages, FALSE otherwise */ function snapshots_demodata(&$messages, $module_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 0 -- get hold of the module-specific translations in $string[] $string = array(); $language_key = $config['language_key']; $filename = dirname(__FILE__) . '/languages/' . $language_key . '/snapshots.php'; if (!file_exists($filename)) { $filename = dirname(__FILE__) . '/languages/en/snapshots.php'; } @(include $filename); if (empty($string)) { $messages[] = 'Internal error: no translations in ' . $filename; return FALSE; } // 1A -- prepare for addition of a few nodes $sort_order = 0; $parent_id = $config['demo_nodes']['news']['node_id']; foreach ($config['demo_nodes'] as $node => $fields) { if ($fields['parent_id'] == $parent_id && $fields['node_id'] != $parent_id) { $sort_order = max($sort_order, $fields['sort_order']); } } $sort_order += 10; // place the snapshots-section at the end of the parent section $nodes = array('snapshots0' => array('parent_id' => $parent_id, 'is_page' => FALSE, 'title' => strtr($string['snapshots0_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots0_link_text'], $config['demo_replace']), 'sort_order' => $sort_order), 'snapshots1' => array('parent_id' => 0, 'is_page' => TRUE, 'is_default' => TRUE, 'title' => strtr($string['snapshots1_title'], $config['demo_replace']), 'link_text' => strtr($string['snapshots1_link_text'], $config['demo_replace']), 'sort_order' => 10, 'module_id' => $module_id, 'style' => "div.thumbnail_image a:hover img { border: 5px solid #00FF00; }\n")); // 1B -- actually add the necessary nodes $now = strftime('%Y-%m-%d %T'); $user_id = $config['user_id']; $area_id = $config['demo_areas']['public']['area_id']; foreach ($nodes as $node => $fields) { $fields['area_id'] = $area_id; $fields['ctime'] = $now; $fields['mtime'] = $now; $fields['atime'] = $now; $fields['owner_id'] = $user_id; if ($fields['parent_id'] == 0) { $fields['parent_id'] = $config['demo_nodes']['snapshots0']['node_id']; // plug in real node_id of 'our' section } if (($node_id = db_insert_into_and_get_id('nodes', $fields, 'node_id')) === FALSE) { $messages[] = $config['demo_string']['error'] . db_errormessage(); $retval = FALSE; } $node_id = intval($node_id); $fields['node_id'] = $node_id; $config['demo_nodes'][$node] = $fields; } // 2 -- Simulate a series of snapshots in the exemplum area data storage // 2A -- copy from module demodata directory to exemplum path $pictures = array("allium.jpg", "calendula.jpg", "cynara.jpg", "lagos.jpg", "lavandula.jpg", "mentha.jpg", "nepeta.jpg", "ocimum.jpg", "origanum.jpg", "petroselinum.jpg", "salvia.jpg", "thymus.jpg"); $thumb_prefix = 'zz_thumb_'; $path_snapshots = '/areas/' . $config['demo_areas']['public']['path'] . '/snapshots'; // relative to $datadir $fullpath_source = dirname(__FILE__) . '/install/demodata'; $fullpath_target = $config['datadir'] . $path_snapshots; if (@mkdir($fullpath_target, 0700) === FALSE) { $messages[] = $config['demo_string']['error'] . "mkdir('{$fullpath_target}')"; $retval = FALSE; } else { @touch($fullpath_target . '/index.html'); // try to "protect" directory foreach ($pictures as $picture) { $filenames = array($picture, $thumb_prefix . $picture); foreach ($filenames as $filename) { if (!@copy($fullpath_source . '/' . $filename, $fullpath_target . '/' . $filename)) { $messages[] = $config['demo_string']['error'] . "copy('{$path_snapshots}/{$filename}')"; $retval = FALSE; } } } } $fields = array('node_id' => $config['demo_nodes']['snapshots1']['node_id'], 'header' => strtr($string['snapshots1_header'], $config['demo_replace']), 'introduction' => strtr($string['snapshots1_introduction'], $config['demo_replace']), 'snapshots_path' => $path_snapshots, 'variant' => 1, 'dimension' => 512, 'ctime' => $now, 'cuser_id' => $user_id, 'mtime' => $now, 'muser_id' => $user_id); if (db_insert_into('snapshots', $fields) === FALSE) { $messages[] = $config['demo_string']['error'] . db_errormessage(); $retval = FALSE; } return $retval; }
/** retrieve all configuration data for this mailpage * * this retrieves all configuration data for this mailpage, * i.e. both the general parameters (header/intro/etc.) and * the full list of configured destination addresses. * Here is a quick reminder of the structure in $config. * <pre> * 'node_id' * 'header' * 'introduction' * 'message' * 'addresses' = ['mailpage_address_id','node_id','sort_order','name','email','description','thankyou'],... * </pre> * * @param int $node_id identifies the page * @return bool|array configuration data in a (nested) array or FALSE on error */ function mailpage_view_get_config($node_id) { // 1 -- generic configuration $table = 'mailpages'; $fields = array('node_id', 'header', 'introduction', 'message'); $where = array('node_id' => intval($node_id)); if (($config = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s(): error retrieving configuration: %s', __FUNCTION__, db_errormessage())); return FALSE; } // 2 -- fetch all configured destinations $table = 'mailpages_addresses'; $fields = '*'; $where = array('node_id' => intval($node_id)); $order = array('sort_order', 'mailpage_address_id'); if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) { logger(sprintf('%s(): error retrieving addresses: %s', __FUNCTION__, db_errormessage())); return FALSE; } $config['addresses'] = $records; // simple 0-based array, not keyed by mailpage_address_id return $config; }
/** add demonstration data to the system * * this routine adds demonstration data to the freshly installed system * * Note * If the theme is installed via the Install Wizard, this routine is * called. However, if a theme is installed as an additional theme * after installation, the {$theme}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @param array $config pertinent data for the new website + demodata foundation * @param array $manifest a copy from the manifest for this theme * @return bool TRUE on success + output via $messages, FALSE otherwise */ function axis_demodata(&$messages, $theme_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 1A -- prepare for setting up demo settings $area_id = intval($config['demo_areas']['public']['area_id']); $theme_id = intval($theme_id); // 1B -- actually setup settings $style = sprintf("#page {\n" . " background-image: url('%s/themes/axis/axis.gif');\n" . "}\n", $config['progwww']); $settings = array('style_usage_static' => '1', 'stylesheet' => 'program/themes/axis/style.css', 'stylesheet_print' => 'program/themes/axis/print.css', 'style_usage_area' => '1', 'style' => $style, 'style_usage_node' => '1'); // 2A -- start with the default settings (copy from theme_properties) $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id); if ($DB->exec($sql) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } // 2B -- update/overwrite the default settings with our own demo-data for area $area_id foreach ($settings as $name => $value) { $fields = array('value' => strval($value)); $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name)); if (db_update('themes_areas_properties', $fields, $where) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** add demonstration data to the system * * this routine adds demonstration data to the freshly installed system * * Note * If the theme is installed via the Install Wizard, this routine is * called. However, if a theme is installed as an additional theme * after installation, the {$theme}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['title'] => the name of the site (as entered by Wilhelmina Bladergroen) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * $config['demo_string'] => array with demo strings from /program/install/languages/LL/demodata.php * $config['demo_replace'] => array with search/replace pairs to 'jazz up' the demo strings * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @param array $config pertinent data for the new website + demodata foundation * @param array $manifest a copy from the manifest for this theme * @return bool TRUE on success + output via $messages, FALSE otherwise */ function cornelia_demodata(&$messages, $theme_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 1A -- prepare for setting up demo settings $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']); $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']); $schoolterms2_id = intval($config['demo_nodes']['schoolterms2']['node_id']); $latestnews_id = intval($config['demo_nodes']['latestnews']['node_id']); $progwww = $config['progwww']; $slogan = $config['demo_string']['welcome_title']; $area_id = intval($config['demo_areas']['public']['area_id']); $theme_id = intval($theme_id); $theme_name = $manifest['name']; $aboutus = $config['demo_string']['aboutus_content']; $email = $config['replyto']; $lorem = strtr('{LOREM}', $config['demo_replace']); $ipsum = strtr('{IPSUM}', $config['demo_replace']); $sidebar_nodelist = sprintf('%d,0,%d,0,-', $latestnews_id, $schoolterms2_id); $style = "#leftmargin { min-height: 300px; }\n" . "#rightmargin { min-height: 300px; }\n"; // 1B -- actually construct settings $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'header_text' => sprintf('<span style="background-color: #FFFF00;">%s</span>', $slogan), 'left_top_html' => sprintf("<img src=\"%s/themes/%s/origanum.jpg\" width=\"120\" height=\"90\" alt=\"\">\n", $progwww, $theme_name), 'left_bottom_html' => sprintf("<div style=\"margin-bottom: 30px;\">\n%s\n</div>\n", $aboutus), 'right_top_html' => $lorem, 'sidebar_nodelist' => $sidebar_nodelist, 'right_bottom_html' => $ipsum, 'footer_text' => sprintf('<b><a href="mailto:%s">%s</a></b>', $email, $email), 'style' => $style); // 2A -- start with the default settings (copy from theme_properties) $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id); if ($DB->exec($sql) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } // 2B -- update/overwrite the default settings with our own demo-data for area $area_id foreach ($settings as $name => $value) { $fields = array('value' => strval($value)); $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name)); if (db_update('themes_areas_properties', $fields, $where) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** construct a title, summary and readmore prompt for an htmlpage page * * this routine uses a heuristic approach to snip N paragraphs from * the actual text in the html-page. Because we cannot be sure that * stripos() is available we resort to first changing any '<P' to * '<p ' and subsequently searching the string until the N+1'th '<p '. * The offset we calculate this way should contain exactly N * paragraphs. Obviously this assumes (dangerous...) that the htmlpage * page_data actually contains paragraphs. However, if not enough '<p * strings are found, the complete page is used. Heuristics... * * @param int $counter is a sequential number identifying the aggregated nodes * @param object &$theme points to theme where the output goes * @param array &$node points to the node record of this htmlpage * @param array &$config points to the aggregator configuration * @return array ordered list of nodes to aggregate (could be empty) */ function aggregator_view_htmlpage($counter, &$theme, &$node, &$config) { $id = strval($counter); // used to make all id's within this item unique // 1 -- outer div holds title+blurb+readmore... $attributes = array('class' => 'aggregator_htmlpage_outer', 'id' => 'aggregator_outer_' . $id); $theme->add_content(html_tag('div', $attributes)); // 2A -- title $attributes = array('class' => 'aggregator_htmlpage_header', 'id' => 'aggregator_header_' . $id); $theme->add_content(' ' . html_tag('h3', $attributes, $node['title'])); // 2B -- blurb (enclosed in inner div) $attributes = array('class' => 'aggregator_htmlpage_inner', 'id' => 'aggregator_inner_' . $id); $theme->add_content(' ' . html_tag('div', $attributes)); // fetch actual content from database (requires knowledge of internals of htmlpage module/table) $table = 'htmlpages'; $node_id = intval($node['node_id']); $where = array('node_id' => $node_id); $fields = array('page_data'); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s: no pagedata (node=%d): %s', __FUNCTION__, $node_id, db_errormessage())); $pagedata = ''; } else { // make SURE we only have lowercase <p followed by a space in the text (easy strpos'ing) $pattern = '/(<[pP])([^a-zA-Z0-9])/'; $replace = '<p $2'; $pagedata = preg_replace($pattern, $replace, $record['page_data']); } $offset = -1; $limit = $config['htmlpage_length']; for ($i = 0; $i <= $limit; ++$i) { if (($offset = strpos($pagedata, '<p ', $offset + 1)) === FALSE) { break; } } if ($offset === FALSE) { // not enough '<p ' seen => show everything $theme->add_content($pagedata . "\n"); } else { $theme->add_content(substr($pagedata, 0, $offset) . "\n"); } $theme->add_content(' </div>'); // 2C -- readmore prompt $anchor = t('htmlpage_more', 'm_aggregator'); $title = t('htmlpage_more_title', 'm_aggregator'); $attr = array('title' => $title); $href = was_node_url($node, NULL, '', $theme->preview_mode); $attributes = array('class' => 'aggregator_htmlpage_more', 'id' => 'aggregator_more_' . $id); $theme->add_content(' ' . html_tag('div', $attributes, html_a($href, NULL, $attr, $anchor))); $theme->add_content(' <div style="clear:both;"></div>'); // 3 -- close outer div $theme->add_content('</div>'); }
/** construct a dialog definition for the workshop configuration * * this generates an array which defines the dialog for workshop configuration. * There are a few plain fields that simply go into the appropriate workshops * record and the save and cancel button. However, there may also be items * related to ACLs. These fields are used to define the user's roles and the * should be presented in a table. We abuse the field names for this purpose: * if the first 3 characters are 'acl' we put the widgets in an HTML-table, otherwise * it is just an ordinary widget. * * Note that in the case of a single simple user without any aquaintances (ie. a user * that is not member of any group) the user is not able to add herself to the list * of authorised users. What is the point of having a _collaborative_ workshop when * you are the only one to collaborate with? (However, it would be fairly easy to force/add * an entry for this user if the tmp table would turn out empty. Maybe later....?) * @param object &$output collects the html output (if any) * @param int $viewonly if TRUE the Save button is not displayed and values cannot be changed * @param int $module_id indicates the id of the crew module in the database (needed for ACL) * @param int $area_id indicates the area where node_id lives (needed for ACL) * @param int $node_id indicates which page we are loooking at (needed for ACL) * @param int $user_id indicates the current user (needed for ACL) * @return array dialog definition */ function crew_get_dialogdef(&$output, $viewonly, $module_id, $area_id, $node_id, $user_id) { global $DB, $USER; static $dialogdef = NULL; if (!is_null($dialogdef)) { // recycle return $dialogdef; } $visibilities = array('2' => array('option' => t('visibility_world_label', 'm_crew'), 'title' => t('visibility_world_title', 'm_crew')), '1' => array('option' => t('visibility_all_label', 'm_crew'), 'title' => t('visibility_all_title', 'm_crew')), '0' => array('option' => t('visibility_workers_label', 'm_crew'), 'title' => t('visibility_workers_title', 'm_crew'))); $roles = array(ACL_ROLE_NONE => array('option' => t('acl_role_none_option', 'admin'), 'title' => t('acl_role_none_title', 'admin')), CREW_ACL_ROLE_READONLY => array('option' => t('crew_acl_role_readonly_option', 'm_crew'), 'title' => t('crew_acl_role_readonly_title', 'm_crew')), CREW_ACL_ROLE_READWRITE => array('option' => t('crew_acl_role_readwrite_option', 'm_crew'), 'title' => t('crew_acl_role_readwrite_title', 'm_crew')), ACL_ROLE_GURU => array('option' => t('acl_role_guru_option', 'admin'), 'title' => t('acl_role_guru_title', 'admin'))); // 1 -- plain & simple fields // make a fresh start with data from the database $dialogdef = array('header' => array('type' => F_ALPHANUMERIC, 'name' => 'header', 'minlength' => 0, 'maxlength' => 240, 'columns' => 30, 'label' => t('header_label', 'm_crew'), 'title' => t('header_title', 'm_crew'), 'viewonly' => $viewonly, 'value' => '', 'old_value' => ''), 'introduction' => array('type' => F_ALPHANUMERIC, 'name' => 'introduction', 'minlength' => 0, 'maxlength' => 32768, 'columns' => 50, 'rows' => 10, 'label' => t('introduction_label', 'm_crew'), 'title' => t('introduction_title', 'm_crew'), 'viewonly' => $viewonly, 'value' => '', 'old_value' => ''), 'visibility' => array('type' => F_RADIO, 'name' => 'visibility', 'value' => 0, 'old_value' => 0, 'options' => $visibilities, 'viewonly' => $viewonly, 'title' => t('visibility_title', 'm_crew'), 'label' => t('visibility_label', 'm_crew'))); $table = 'workshops'; $fields = array('header', 'introduction', 'visibility'); $where = array('node_id' => intval($node_id)); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s(): error retrieving CREW configuration: %s', __FUNCTION__, db_errormessage())); $output->add_message(t('error_retrieving_data', 'admin')); } else { foreach ($record as $name => $value) { $dialogdef[$name]['value'] = $dialogdef[$name]['old_value'] = $value; } } $sql = sprintf('DROP TEMPORARY TABLE IF EXISTS %screw_tmp', $DB->prefix); $retval = $DB->exec($sql); if ($USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) { // Allow $USER to set/edit any user's permission because she is already able // to manipulate useraccounts, _all_ useraccounts. We are sure that $USER is a // valid user with at least JOB_PERMISSION_STARTCENTER or else we would not be here. $sql = sprintf('CREATE TEMPORARY TABLE %screw_tmp ' . 'SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u ' . 'LEFT JOIN %sacls_modules_nodes amn ' . 'ON amn.acl_id = u.acl_id AND amn.module_id = %d AND amn.node_id = %d ' . 'ORDER BY u.full_name', $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id); } else { // Only allow $USER to set permissions for all her acquaintances, ie. all users // that are members of the group(s) that $USER is a also member of. $sql = sprintf('CREATE TEMPORARY TABLE %screw_tmp ' . 'SELECT DISTINCT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u ' . 'INNER JOIN %susers_groups_capacities ugc1 USING(user_id) ' . 'INNER JOIN %susers_groups_capacities ugc2 USING(group_id) ' . 'LEFT JOIN %sacls_modules_nodes amn ' . 'ON amn.acl_id = u.acl_id AND amn.module_id = %d AND amn.node_id = %d ' . 'WHERE ugc2.user_id = %d ' . 'ORDER BY u.full_name', $DB->prefix, $DB->prefix, $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id, $user_id); } $retval = $DB->exec($sql); // at this point we have a temporary table with all 'editable' accounts // we first add those to the dialogdef. $table = 'crew_tmp'; $fields = '*'; $where = ''; $order = array('full_name', 'username'); if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) { logger(sprintf('%s(): error retrieving elegible CREW-members: %s', __FUNCTION__, db_errormessage())); $output->add_message(t('error_retrieving_data', 'admin')); } else { foreach ($records as $record) { $acl_id = intval($record['acl_id']); $name = 'acl_rw_' . $acl_id; $dialogdef[$name] = array('type' => F_LISTBOX, 'name' => $name, 'value' => is_null($record['permissions_modules']) ? 0 : $record['permissions_modules'], 'old_value' => $record['permissions_modules'], 'acl_id' => $acl_id, 'options' => $roles, 'viewonly' => $viewonly, 'title' => $record['username'], 'label' => $record['full_name']); } } // the next step is to generate a list of any OTHER accounts that happen to have // permissions for this module on this node other than ACL_ROLE_NONE. // This list consists of a few UNIONs that effectively yields all accounts that // somehow have a non-0 permissions_modules, either global (acls), any node for // this module (acls_modules), any node within this area (acls_modules_area), // any node that is an ancestor of node_id (acls_modules_nodes) OR this specific // node for a user that is NOT an acquaintance (ie. who is not in the temp table). // Note that we don't check the ancestors (parents) when node happens to be at // the top level within the area, ie. when parent is 0. We also peek inside // 'acls_areas' and 'acls_nodes'. Pfew, complicated... // All these OTHER accounts cannot be manipulated by $USER because all accounts // would then be in the temp table, so there. // Since there may be more records for the same user (or rather acl_id), we need // to drill down the results. As all permissions are additive we can simply OR // these together per acl_id/user which yields a single combined role for that user. $tree = tree_build($area_id); $ancestors = array(); for ($next_id = $tree[$node_id]['parent_id']; $next_id; $next_id = $tree[$next_id]['parent_id']) { $ancestors[] = $next_id; } unset($tree); $sql = empty($ancestors) ? '' : sprintf('SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_modules_nodes amn USING (acl_id) ' . 'WHERE amn.permissions_modules <> 0 AND amn.module_id = %d AND amn.node_id IN (%s)', $DB->prefix, $DB->prefix, $module_id, join(',', $ancestors)) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, an.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_nodes an USING (acl_id) ' . 'WHERE an.permissions_modules <> 0 AND an.node_id IN (%s)', $DB->prefix, $DB->prefix, join(',', $ancestors)) . ' UNION '; $sql .= sprintf('SELECT u.acl_id, u.username, u.full_name, a.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls a USING (acl_id) ' . 'WHERE a.permissions_modules <> 0', $DB->prefix, $DB->prefix) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, am.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_modules am USING (acl_id) ' . 'WHERE am.permissions_modules <> 0 AND am.module_id = %d', $DB->prefix, $DB->prefix, $module_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, aa.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_areas aa USING (acl_id) ' . 'WHERE aa.permissions_modules <> 0 AND aa.area_id = %d', $DB->prefix, $DB->prefix, $area_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, ama.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_modules_areas ama USING (acl_id) ' . 'WHERE ama.permissions_modules <> 0 AND ama.module_id = %d AND ama.area_id = %d', $DB->prefix, $DB->prefix, $module_id, $area_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, an.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_nodes an USING (acl_id) ' . 'WHERE an.permissions_modules <> 0 AND an.node_id = %d', $DB->prefix, $DB->prefix, $node_id) . ' UNION ' . sprintf('SELECT u.acl_id, u.username, u.full_name, amn.permissions_modules ' . 'FROM %susers u INNER JOIN %sacls_modules_nodes amn USING (acl_id) ' . 'LEFT JOIN %screw_tmp tmp USING(acl_id) ' . 'WHERE amn.permissions_modules <> 0 AND amn.module_id = %d AND amn.node_id = %d ' . 'AND tmp.acl_id IS NULL ', $DB->prefix, $DB->prefix, $DB->prefix, $module_id, $node_id) . 'ORDER BY full_name, acl_id'; if (($result = $DB->query($sql)) === FALSE) { logger(sprintf('%s(): error retrieving other account names: %s', __FUNCTION__, db_errormessage())); $output->add_message(t('error_retrieving_data', 'admin')); } else { if ($result->num_rows > 0) { $records = array(); while (($record = $result->fetch_row_assoc()) !== FALSE) { $acl_id = intval($record['acl_id']); if (isset($records[$acl_id])) { $records[$acl_id]['permissions_modules'] |= intval($record['permissions_modules']); } else { $records[$acl_id] = $record; } } $result->close(); foreach ($records as $acl_id => $record) { $name = 'acl_ro_' . $acl_id; $dialogdef[$name] = array('type' => F_LISTBOX, 'name' => $name, 'value' => is_null($record['permissions_modules']) ? 0 : $record['permissions_modules'], 'options' => $roles, 'viewonly' => TRUE, 'title' => $record['username'], 'label' => $record['full_name']); } } } if (!$viewonly) { $dialogdef['button_save'] = dialog_buttondef(BUTTON_SAVE); } $dialogdef['button_cancel'] = dialog_buttondef(BUTTON_CANCEL); return $dialogdef; }
/** add demonstration data to the system * * this routine adds demonstration data to the freshly installed system * * Note * If the theme is installed via the Install Wizard, this routine is * called. However, if a theme is installed as an additional theme * after installation, the {$theme}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @param array $config pertinent data for the new website + demodata foundation * @param array $manifest a copy from the manifest for this theme * @return bool TRUE on success + output via $messages, FALSE otherwise */ function schoolyard_demodata(&$messages, $theme_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 0 -- get hold of our translations in $string[] $string = array(); $language_key = $config['language_key']; $filename = dirname(__FILE__) . '/languages/' . $language_key . '/schoolyard.php'; if (!file_exists($filename)) { $filename = dirname(__FILE__) . '/languages/en/schoolyard.php'; } @(include $filename); if (empty($string)) { $messages[] = 'Internal error: no translations in ' . $filename; return FALSE; } // 1A -- prepare for setting up demo settings $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']); $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']); $www = $config['www']; $area_id = intval($config['demo_areas']['public']['area_id']); $theme_id = intval($theme_id); // 1B -- actually setup settings $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'show_breadcrumb_trail' => '1', 'logo_image' => 'program/themes/schoolyard/waslogo.png', 'logo_width' => '284', 'logo_height' => '71', 'style_usage_static' => '1', 'stylesheet' => 'program/themes/schoolyard/style.css', 'stylesheet_print' => 'program/themes/schoolyard/print.css', 'style_usage_area' => '1', 'style' => '', 'style_usage_node' => '1'); // 2A -- start with the default settings (copy from theme_properties) $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id); if ($DB->exec($sql) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } // 2B -- update/overwrite the default settings with our own demo-data for area $area_id foreach ($settings as $name => $value) { $fields = array('value' => strval($value)); $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name)); if (db_update('themes_areas_properties', $fields, $where) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** quick and dirty logfile viewer * * this constructs a table of the HTML-variety with the contents of the logtable. * fields displayed are: datim, IP-address, username, logpriority and message * we use a LEFT JOIN in order to get to a meaningful username rather than a numeric user_id * an attempt is made to start with the last page of the logs because that would probably * be the most interesting part. We paginate the log in order to keep it manageable. * * <Rant><br> * I used to use the built-in constants like LOG_INFO and LOG_DEBUG to allow for different levels * of logging (see {@link logger()}). To my complete surprise logging didn't work at all on * Windows (it did on Linux). The reason was that LOG_DEBUG and LOG_INFO and LOG_NOTICE are all * defined to be the same value. WTF? Any test based on LOG_DEBUG and LOG_INFO being different * would fail, hence no logging at all. The mind boggles! So, instead of using built-in constants * I had to define my own and do a global search&replace. Aaarghhhhhh!!!!<br> * </Rant><br> * * @param object &$output collects output to show to user * @return void output displayed via $output * @todo should we allow for fancy selection mechanisms on the logfile or is that over the top? */ function task_logview(&$output) { global $CFG, $WAS_SCRIPT_NAME, $DB; static $priorities = array(WLOG_EMERG => 'LOG_EMERG', WLOG_ALERT => 'LOG_ALERT', WLOG_CRIT => 'LOG_CRIT', WLOG_ERR => 'LOG_ERR', WLOG_WARNING => 'LOG_WARNING', WLOG_NOTICE => 'LOG_NOTICE', WLOG_INFO => 'LOG_INFO', WLOG_DEBUG => 'LOG_DEBUG'); // 0 -- at least we allow the user to navigate away if something goes wrong $output->set_helptopic('logview'); show_tools_menu($output, TASK_LOGVIEW); // 1A -- how many messages are there anyway? $table = 'log_messages'; $where = ''; // could be used to select per user, per priority, etc. For now: always select everything if (($record = db_select_single_record($table, 'COUNT(log_message_id) AS messages', $where)) === FALSE) { $output->add_content('<h2>' . t('menu_logview', 'admin') . '</h2>'); $output->add_content(t('logview_error', 'admin')); $output->add_message(t('logview_error', 'admin')); logger(sprintf('%s(): cannot retrieve log message count: %s', __FUNCTION__, db_errormessage())); return; } // 1B -- if there are no message we leave if (($num_messages = intval($record['messages'])) < 1) { $output->add_content('<h2>' . t('menu_logview', 'admin') . '</h2>'); $output->add_content(t('logview_no_messages', 'admin')); $output->add_message(t('logview_no_messages', 'admin')); logger(sprintf('%s(): no messages to show', __FUNCTION__), WLOG_DEBUG); return; } // 2 -- which part of the logs do they want to see? (calculate/retrieve offset and limit) $limit = get_parameter_int('limit', $CFG->pagination_height); $limit = max(1, $limit); // make sure 1 <= $limit $offset = intval(floor($num_messages / $limit)) * $limit; // attempt to start at begin of LAST page $offset = get_parameter_int('offset', max($offset, 0)); $offset = max(min($num_messages - 1, $offset), 0); // make sure 0 <= $offset < $num_messages // 3 -- show the pagination in the page header (if necessary) if ($num_messages <= $limit && $offset == 0) { // listing fits on a single screen $header = '<h2>' . t('menu_logview', 'admin') . '</h2>'; } else { // pagination necessary, tell user where we are $param = array('{FIRST}' => strval($offset + 1), '{LAST}' => strval(min($num_messages, $offset + $limit)), '{TOTAL}' => strval($num_messages)); $header = '<h2>' . t('menu_logview', 'admin') . ' ' . t('pagination_count_of_total', 'admin', $param) . '</h2>'; $parameters = array('job' => JOB_TOOLS, 'task' => TASK_LOGVIEW); $output->add_pagination($WAS_SCRIPT_NAME, $parameters, $num_messages, $limit, $offset, $CFG->pagination_width); } // 4 -- retrieve the selected messages (including optional username via LEFT JOIN) $sql = sprintf('SELECT l.datim, l.remote_addr, l.priority, l.user_id, u.username, l.message ' . 'FROM %slog_messages l LEFT JOIN %susers u USING (user_id) ' . 'ORDER BY l.datim, l.log_message_id', $DB->prefix, $DB->prefix); if (($DBResult = $DB->query($sql, $limit, $offset)) === FALSE) { $output->add_message(t('logview_error', 'admin')); logger(sprintf('%s(): cannot retrieve log messages: %s', __FUNCTION__, db_errormessage())); return; } $records = $DBResult->fetch_all_assoc(); $DBResult->close(); // 5A -- setup a table with a header $index = $offset + 1; $output->add_content($header); $class = 'header'; $attributes = array('class' => $class, 'align' => 'right'); $output->add_content('<p>'); $output->add_content(html_table(array('cellpadding' => '3'))); $output->add_content(' ' . html_table_row($attributes)); $output->add_content(' ' . html_table_head($attributes, t('logview_nr', 'admin'))); $attributes['align'] = 'left'; $output->add_content(' ' . html_table_head($attributes, t('logview_datim', 'admin'))); $output->add_content(' ' . html_table_head($attributes, t('logview_remote_addr', 'admin'))); $output->add_content(' ' . html_table_head($attributes, t('logview_user_id', 'admin'))); $output->add_content(' ' . html_table_head($attributes, t('logview_priority', 'admin'))); $output->add_content(' ' . html_table_head($attributes, t('logview_message', 'admin'))); $output->add_content(' ' . html_table_row_close()); // 5B -- step through the recordset and dump into the table foreach ($records as $record) { $class = $class == 'odd' ? 'even' : 'odd'; $priority = isset($priorities[$record['priority']]) ? $priorities[$record['priority']] : strval(intval($record['priority'])); $attributes = array('class' => $class); $output->add_content(' ' . html_table_row($attributes)); $attributes['align'] = 'right'; $output->add_content(' ' . html_table_cell($attributes, strval($index++))); $attributes['align'] = 'left'; $output->add_content(' ' . html_table_cell($attributes, htmlspecialchars($record['datim']))); $output->add_content(' ' . html_table_cell($attributes, htmlspecialchars($record['remote_addr']))); $output->add_content(' ' . html_table_cell($attributes, htmlspecialchars($record['username']))); $output->add_content(' ' . html_table_cell($attributes, $priority)); $output->add_content(' ' . html_table_cell($attributes, htmlspecialchars($record['message']))); $output->add_content(' ' . html_table_row_close()); } // 5C -- all done $output->add_content(html_table_close()); $output->add_content('<p>'); }
/** retrieve an array with 0, 1 or more records with permissions from table 'acls_nodes' * * this constructs an array with all permissions from the 'acls_nodes' table for the * specified acl $acl_id and optionally for all related acl_id's in $related_acls and optional * nodes. The resulting array is keyed by node_id and acl_id. * * Note that by making the result keyed by node_id first (and then acl_id) it becomes possible * to step throug a list of nodes and have 0,1 or more acls for that node in a single array, * e.g. $acls = $permissions[16] yields the selected acls that apply to node 16. That is handy * when constructing dialogs iterating through nodes such as pagemanager permissions. * * @param array $area_id the area where the nodes reside * @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 0, 1 or more acls-records keyed by node_id and acl_id */ function get_permissions_nodes_in_area($area_id, $acl_id, $related_acls = NULL) { global $DB; $fields = '*'; // 1A -- selection of acls via '((an.acl_id = 1) OR (an.acl_id = 2) OR (an.acl_id = 3))' $where = sprintf("(an.acl_id = %d)", $acl_id); if (!empty($related_acls)) { foreach ($related_acls as $id => $acl) { $where .= sprintf(" OR (an.acl_id = %d)", $id); } $where = "(" . $where . ")"; } $sql = sprintf("SELECT an.* " . "FROM %sacls_nodes an " . "INNER JOIN %snodes n ON ((an.node_id = n.node_id) AND (n.area_id = %d)) " . "WHERE %s", $DB->prefix, $DB->prefix, $area_id, $where); // 2 -- fetch raw data from the database in a single set of database records if (($DBResult = $DB->query($sql)) === FALSE) { logger('aclmanager(): cannot retrieve nodes permissions in area $area_id: ' . db_errormessage()); return array(); } $records = $DBResult->fetch_all_assoc(); $DBResult->close(); // 3 -- construct a 2D-array keyed with node_id and acl_id (in that order) $permissions = array(); foreach ($records as $record) { $node_id = intval($record['node_id']); $acl_id = intval($record['acl_id']); $permissions[$node_id][$acl_id] = $record; } unset($records); return $permissions; }
/** add demonstration data to the system * * this routine adds demonstration data to the freshly installed system * * Note * If the theme is installed via the Install Wizard, this routine is * called. However, if a theme is installed as an additional theme * after installation, the {$theme}_demodata() routine is never called. * This is because the only time you know that demodata is installed is * when the Install Wizard runs. If we're called from admin.php, the * webmaster may have already deleted existing (core) demodata so you * never can be sure what to expect. To put it another way: it is hard * to re-construct $config when we're NOT the Instal Wizard. * * The array $config contains the following information. * * <code> * $config['language_key'] => install language code (eg. 'en') * $config['dir'] => path to CMS Root Directory (eg. /home/httpd/htdocs) * $config['www'] => URL of CMS Root Directory (eg. http://exemplum.eu) * $config['progdir'] => path to program directory (eg. /home/httpd/htdocs/program) * $config['progwww'] => URL of program directory (eg. http://exemplum.eu/program) * $config['datadir'] => path to data directory (eg. /home/httpd/wasdata/a1b2c3d4e5f6) * $config['user_username'] => userid of webmaster (eg. wblader) * $config['user_full_name'] => full name of webmaster (eg. Wilhelmina Bladergroen) * $config['user_email'] => email of webmaster (eg. w.bladergroen@exemplum.eu) * $config['user_id'] => numerical user_id (usually 1) * $config['demo_salt'] => password salt for all demodata accounts * $config['demo_password'] => password for all demodata accounts * $config['demo_areas'] => array with demo area data * $config['demo_groups'] => array with demo group data * $config['demo_users'] => array with demo user data * $config['demo_nodes'] => array with demo node data * </code> * * With this information, we can add a demonstration configuration for the public area, * which shows off the possibilities. * * @param array &$messages collects the (error) messages * @param int $theme_id the key for this theme in the themes table * @param array $config pertinent data for the new website + demodata foundation * @param array $manifest a copy from the manifest for this theme * @return bool TRUE on success + output via $messages, FALSE otherwise */ function rosalina_demodata(&$messages, $theme_id, $config, $manifest) { global $DB; $retval = TRUE; // assume success // 0 -- get hold of our translations in $string[] $string = array(); $language_key = $config['language_key']; $filename = dirname(__FILE__) . '/languages/' . $language_key . '/rosalina.php'; if (!file_exists($filename)) { $filename = dirname(__FILE__) . '/languages/en/rosalina.php'; } @(include $filename); if (empty($string)) { $messages[] = 'Internal error: no translations in ' . $filename; return FALSE; } // 1A -- prepare for setting up demo settings $quicktop_section_id = intval($config['demo_nodes']['quicktop']['node_id']); $quickbottom_section_id = intval($config['demo_nodes']['quickbottom']['node_id']); $www = $config['www']; $area_id = intval($config['demo_areas']['public']['area_id']); $theme_id = intval($theme_id); // Hotspot 1 - the blue jigsaw piece leads to admin.php $hotspot_1 = implode(';', array('poly', '0,0,37,37,52,22,52,0', $www . '/admin.php', $string['demo_admin_php_title'])); // Hotspot 2 - the gray jigsaw piece leads to login/logout (index.php) $hotspot_2 = implode(';', array('poly', '0,1,37,38,5,70,0,70', $www . '/index.php?login=1', $string['demo_index_php_login_title'], $www . '/index.php?logout=1', $string['demo_index_php_logout_title'])); // Hotspot 3 - the red jigsaw piece leads to the websiteatschool project website in a new window $hotspot_3 = implode(';', array('poly', '6,70,52,24,52,70', 'http://websiteatschool.eu', $string['demo_websiteatschool_eu_title'], '', '', '_blank')); // Hotspot 4 - the red word 'Website' leads to the defaul area (via index.php without parameters) $hotspot_4 = implode(';', array('rect', '53,17,157,58', $www . '/index.php', $string['demo_index_php_title'])); // Hotspot 5 - the gray word '@' leads to the demodata contact page $hotspot_5 = implode(';', array('circle', '173,36,15', sprintf('%s/index.php?node=%d', $www, $config['demo_nodes']['contact']['node_id']), $config['demo_nodes']['contact']['title'])); // Hotspot 6 - the blue word 'School' leads explicitly to the public area (via index.php?area=NN) $hotspot_6 = implode(';', array('rect', '189,9,279,58', sprintf('%s/index.php?area=%d', $www, $area_id), $config['demo_areas']['public']['title'])); // 1B -- actually setup settings $settings = array('quicktop_section_id' => strval($quicktop_section_id), 'quickbottom_section_id' => strval($quickbottom_section_id), 'show_breadcrumb_trail' => '1', 'logo_image' => 'program/themes/rosalina/waslogo.png', 'logo_width' => '284', 'logo_height' => '71', 'logo_title' => $string['demo_logo_title'], 'logo_alt' => $string['demo_logo_alt'], 'logo_hotspots' => '6', 'logo_hotspot_1' => $hotspot_1, 'logo_hotspot_2' => $hotspot_2, 'logo_hotspot_3' => $hotspot_3, 'logo_hotspot_4' => $hotspot_4, 'logo_hotspot_5' => $hotspot_5, 'logo_hotspot_6' => $hotspot_6, 'logo_hotspot_7' => '', 'logo_hotspot_8' => '', 'style_usage_static' => '1', 'stylesheet' => 'program/themes/rosalina/style.css', 'style_usage_area' => '1', 'style' => '', 'style_usage_node' => '1', 'hvmenu_LowBgColor' => '#FFCCCC', 'hvmenu_LowSubBgColor' => '#FF9999', 'hvmenu_HighBgColor' => '#CCCCFF', 'hvmenu_HighSubBgColor' => '#CCCCFF', 'hvmenu_FontLowColor' => '#000000', 'hvmenu_FontSubLowColor' => '#000000', 'hvmenu_FontHighColor' => '#000000', 'hvmenu_FontSubHighColor' => '#000000', 'hvmenu_BorderColor' => '#666666', 'hvmenu_BorderSubColor' => '#666666', 'hvmenu_BorderWidth' => '1', 'hvmenu_BorderBtwnElmnts' => '1', 'hvmenu_FontFamily' => 'Verdana,sans-serif', 'hvmenu_FontSize' => '9.5', 'hvmenu_FontBold' => '1', 'hvmenu_FontItalic' => '0', 'hvmenu_MenuTextCentered' => 'left', 'hvmenu_MenuCentered' => 'left', 'hvmenu_MenuVerticalCentered' => 'top', 'hvmenu_ChildOverlap' => '0.0', 'hvmenu_ChildVerticalOverlap' => '0.0', 'hvmenu_StartTop' => '0', 'hvmenu_StartLeft' => '0', 'hvmenu_LeftPaddng' => '8', 'hvmenu_TopPaddng' => '2', 'hvmenu_FirstLineHorizontal' => '1', 'hvmenu_DissapearDelay' => '1000', 'hvmenu_MenuWrap' => '1', 'hvmenu_RightToLeft' => '0', 'hvmenu_UnfoldsOnClick' => '0', 'hvmenu_ShowArrow' => '1', 'hvmenu_KeepHilite' => '1', 'hvmenu_Arrws' => 'tri.gif,5,10,tridown.gif,10,5,trileft.gif,5,10', 'menu_top' => '120,10,300,20', 'menu_sub' => '150,10,500,20'); // 2A -- start with the default settings (copy from theme_properties) $sql = sprintf('INSERT INTO %s%s(area_id,theme_id,name,type,value,extra,sort_order,description) ' . 'SELECT %d AS area_id,theme_id,name,type,value,extra,sort_order,description ' . 'FROM %s%s ' . 'WHERE theme_id = %d', $DB->prefix, 'themes_areas_properties', $area_id, $DB->prefix, 'themes_properties', $theme_id); if ($DB->exec($sql) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } // 2B -- update/overwrite the default settings with our own demo-data for area $area_id foreach ($settings as $name => $value) { $fields = array('value' => strval($value)); $where = array('area_id' => $area_id, 'theme_id' => $theme_id, 'name' => strval($name)); if (db_update('themes_areas_properties', $fields, $where) === FALSE) { $messages[] = __FUNCTION__ . '(): ' . db_errormessage(); $retval = FALSE; } } return $retval; }
/** save the modified configuration parameters to the database * * @param object &$output the object that collects the output * @result FALSE on error + error messages added to messages part of output or TRUE and data stored to database. * @uses dialog_validate() */ function save_data(&$output) { if (empty($this->dialogdef)) { $this->dialogdef = $this->get_dialogdef(); } if (!dialog_validate($this->dialogdef)) { foreach ($this->dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $output->add_message($item['error_messages']); } } return FALSE; } $errors = 0; $records_changed = 0; $records_unchanged = 0; if (is_array($this->records)) { foreach ($this->records as $id => $record) { $name = $this->prefix . 'record_' . strval($id); if (isset($this->dialogdef[$name])) { if ($this->dialogdef[$name]['value'] != $this->dialogdef[$name]['old_value']) { ++$records_changed; $fields = array('value' => strval($this->dialogdef[$name]['value'])); $where = array($this->keyfield => $id); if (db_update($this->table, $fields, $where) === FALSE) { logger('configassistant: error saving config value: ' . db_errormessage()); ++$errors; } else { logger(sprintf("configassistant: success updating %s[%s] => '%s'", $this->table, $id, strval($this->dialogdef[$name]['value'])), WLOG_DEBUG); } } else { ++$records_unchanged; } // if (modified) } // if (data available) } // foreach } // if (records) logger(sprintf('configassistant: save configuration in table %s: unchanged: %d, changed: %d, errors: %d', $this->table, $records_unchanged, $records_changed, $errors), WLOG_DEBUG); if ($errors == 0) { $output->add_message(t('success_saving_data', 'admin')); $retval = TRUE; } else { $output->add_message(t('errors_saving_data', 'admin', array('{ERRORS}' => strval($errors)))); $retval = FALSE; } return $retval; }
/** 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 }
/** generate a list of (virtual) directories for users this user can access * * This generates a list of (virtual) user directories for which this * user has access permissions. The list is ordered by full name. * * @return array list of available user directories for this user * @uses $USER; * @uses $CFG; */ function get_entries_users() { global $USER, $CFG; $entries = array(); if ($USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) { $table = 'users'; $fields = array('user_id', 'username', 'full_name', 'is_active', 'path'); $where = ''; $order = array('full_name', 'username'); if (($users = db_select_all_records($table, $fields, $where, $order, 'user_id')) === FALSE) { logger(sprintf('%s.%s(): cannot retrieve users list: %s', __CLASS__, __FUNCTION__, db_errormessage())); $users = array(); } } else { $users = array(array('user_id' => $USER->user_id, 'username' => $USER->username, 'full_name' => $USER->full_name, 'is_active' => TRUE, 'path' => $USER->path)); } if (count($users) > 0) { foreach ($users as $user_id => $user) { $name = $user['path']; $path = '/users/' . $name; $vname = $user['full_name']; $vpath = t('filemanager_users', 'admin') . '/' . $vname; $entries[$name] = array('name' => $name, 'path' => $path, 'vname' => $vname, 'vpath' => $vpath, 'mtime' => filemtime($CFG->datadir . $path), 'size' => 0, 'is_file' => FALSE, 'title' => t('filemanager_navigate_to', 'admin', array('{DIRECTORY}' => $vpath))); } } return $entries; }