mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-30 16:47:14 +09:00
- The search filter does not support Cyrillic - Also adding more __esc() to title and value attributes - Also adding more missing i18n via audit
1531 lines
58 KiB
PHP
1531 lines
58 KiB
PHP
<?php
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2017 The Cacti Group |
|
|
| |
|
|
| This program is free software; you can redistribute it and/or |
|
|
| modify it under the terms of the GNU General Public License |
|
|
| as published by the Free Software Foundation; either version 2 |
|
|
| of the License, or (at your option) any later version. |
|
|
| |
|
|
| This program is distributed in the hope that it will be useful, |
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
| GNU General Public License for more details. |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDTool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
| This code is designed, written, and maintained by the Cacti Group. See |
|
|
| about.php and/or the AUTHORS file for specific developer information. |
|
|
+-------------------------------------------------------------------------+
|
|
| http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
/**
|
|
* Create or update aggregate graph.
|
|
* Save all graph definitions, but omit graph items. Wipe out host_id and graph_template_id.
|
|
*
|
|
* @param int $local_graph_id - ID of an already existing aggregate graph.
|
|
* @param int $graph_template_id - ID of the corresponding graph_teamplate.
|
|
* @param string $graph_title - Title for new graph.
|
|
* @param int $aggregate_template_id - ID of aggregate template (0 if no template).
|
|
* @param array $new_data - Key/value pairs with new graph data.
|
|
*
|
|
* @return int ID of the new graph.
|
|
*/
|
|
function aggregate_graph_save($_local_graph_id, $_graph_template_id, $_graph_title, $_aggregate_template_id = 0, $graph_data = array()) {
|
|
/* suppress warnings */
|
|
error_reporting(E_ALL);
|
|
|
|
/* install own error handler */
|
|
set_error_handler('aggregate_error_handler');
|
|
|
|
cacti_log(__FUNCTION__ . ' local_graph: ' . $_local_graph_id . ' template: ' . $_graph_template_id . ' graph title: ' . $_graph_title . ' aggregate template: ' . $_aggregate_template_id, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* store basic graph info */
|
|
$local_graph_id = aggregate_graph_local_save($_local_graph_id);
|
|
|
|
/* store extra graph data */
|
|
$graph_templates_graph_id = aggregate_graph_templates_graph_save($local_graph_id, $_graph_template_id, $_graph_title, $_aggregate_template_id, $graph_data);
|
|
|
|
/* restore original error handler */
|
|
restore_error_handler();
|
|
|
|
/* return the id of the newly inserted graph */
|
|
return $local_graph_id;
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates or updates basic aggregate graph data in graph_local.
|
|
*
|
|
* @param int $id - ID of existing aggregate graph if updating or 0 if creating a new one.
|
|
*
|
|
* @return int ID of graph.
|
|
*/
|
|
function aggregate_graph_local_save($id = 0) {
|
|
cacti_log(__FUNCTION__ . ' local_graph: ' . $id, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* create or update entry: graph_local */
|
|
$local_graph['id'] = (isset($id) ? $id : 0);
|
|
$local_graph['graph_template_id'] = 0; # no templating
|
|
$local_graph['host_id'] = 0; # no host to be referred to
|
|
$local_graph['snmp_query_id'] = 0; # no templating
|
|
$local_graph['snmp_index'] = ''; # no templating, may hold string data
|
|
|
|
return sql_save($local_graph, 'graph_local');
|
|
}
|
|
|
|
|
|
/**
|
|
* Create or update aggregate graphs data in graph_templates_graph.
|
|
* Graph must already exist in graph_local eg. local_graph_id must never be 0
|
|
*
|
|
* @param int $local_graph_id - ID of graph.
|
|
* @param int $graph_template_id - Graph template this graph is based on.
|
|
* @param string $graph_title - Title of graph. Used only for new graphs.
|
|
* @param int $aggregate_template_id - ID of aggregate template this graph is based on (0 if not aggregate template based).
|
|
* @param array $new_data - Key/value pairs with new graph data.
|
|
*
|
|
* @return int ID of record in graph_templates_graph
|
|
*/
|
|
function aggregate_graph_templates_graph_save($local_graph_id, $graph_template_id, $graph_title = '', $aggregate_template_id = 0, $new_data = array()) {
|
|
cacti_log(__FUNCTION__ . ' local_graph: ' . $local_graph_id . ' template: ' . $graph_template_id . ' title: ' . $graph_title . ' aggregate template: '. $aggregate_template_id, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* base graph must exist */
|
|
if ($local_graph_id < 1) {
|
|
return 0;
|
|
}
|
|
|
|
$graph_data = array();
|
|
$existing_data = db_fetch_row_prepared('SELECT *
|
|
FROM graph_templates_graph
|
|
WHERE local_graph_id = ?',
|
|
array($local_graph_id));
|
|
|
|
$template_data = db_fetch_row_prepared('SELECT *
|
|
FROM graph_templates_graph
|
|
WHERE graph_template_id = ?
|
|
AND local_graph_id=0',
|
|
array($graph_template_id));
|
|
|
|
if ($aggregate_template_id > 0) {
|
|
/* override selected fields from template data with aggregate template data */
|
|
$aggregate_data = db_fetch_row_prepared('SELECT *
|
|
FROM aggregate_graph_templates_graph
|
|
WHERE aggregate_template_id = ?',
|
|
array($aggregate_template_id));
|
|
|
|
if (sizeof($aggregate_data)) {
|
|
foreach ($aggregate_data as $field => $value) {
|
|
if (substr($field, 0, 2) == 't_' && $value == 'on') {
|
|
$value_field_name = substr($field, 2);
|
|
$template_data[$value_field_name] = $aggregate_data[$value_field_name];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sizeof($existing_data) == 0) {
|
|
/* this is a new graph, use template data */
|
|
$graph_data = $template_data;
|
|
|
|
$graph_data['id'] = 0;
|
|
$graph_data['title'] = $graph_title;
|
|
$graph_data['title_cache'] = $graph_title;
|
|
} elseif ($aggregate_template_id > 0) {
|
|
/* this graph exists and is templated from aggregate template,
|
|
* use template data */
|
|
$graph_data = $template_data;
|
|
|
|
$graph_data['id'] = $existing_data['id'];
|
|
$graph_data['title'] = $existing_data['title'];
|
|
$graph_data['title_cache'] = $existing_data['title_cache'];
|
|
} else {
|
|
/* this is an existing graph and not templated from aggregate,
|
|
* re-use its old data */
|
|
$graph_data = $existing_data;
|
|
}
|
|
|
|
if ($aggregate_template_id == 0) {
|
|
/* now use new data */
|
|
$graph_data = array_merge($graph_data, $new_data);
|
|
}
|
|
|
|
/* safety check - don't allow empty titles */
|
|
if ($graph_title != '') {
|
|
$graph_data['title'] = $graph_title;
|
|
$graph_data['title_cache'] = $graph_title;
|
|
}
|
|
|
|
$graph_data['local_graph_id'] = $local_graph_id;
|
|
$graph_data['local_graph_template_graph_id'] = 0; # no templating
|
|
$graph_data['graph_template_id'] = 0; # no templating
|
|
|
|
$graph_templates_graph_id = sql_save($graph_data, 'graph_templates_graph');
|
|
|
|
/* update title cache */
|
|
if (!empty($graph_templates_graph_id)) {
|
|
update_graph_title_cache($local_graph_id);
|
|
}
|
|
|
|
return $graph_templates_graph_id;
|
|
}
|
|
|
|
|
|
/** aggregate_graphs_insert_graph_items - inserts all graph items of an existing graph
|
|
* @param int $_new_graph_id - id of the new graph
|
|
* @param int $_old_graph_id - id of the old graph
|
|
* @param int $_graph_template_id - template id of the old graph if the old graph is 0
|
|
* @param int $_skip - graph items to be skipped, array starts at 1
|
|
* @param int $_totali - graph items to be totaled, array starts at 1
|
|
* @param bool $_hr - graph items that should have a <HR>
|
|
* @param int $_graph_item_sequence - sequence number of the next graph item to be inserted
|
|
* @param int $_selected_graph_index - index of current graph to be inserted
|
|
* @param array $_color_templates - the color templates to be used
|
|
* @param array $_graph_item_types - graph_type_ids to override types from original graph item
|
|
* @param array $_cdefs - cdef_ids to override cdef from original graph item
|
|
* @param int $_graph_type - conversion to AREA/STACK or LINE required?
|
|
* @param int $_gprint_prefix - prefix for the legend line
|
|
* @param int $_total - Totalling: graph items AND/OR legend
|
|
* @param int $_total_type - Totalling: SIMILAR/ALL data sources
|
|
* @param array $member_graph - Totalling: Used for determining the consolidation function id
|
|
* @return int - id of the next graph item to be inserted
|
|
* */
|
|
function aggregate_graphs_insert_graph_items($_new_graph_id, $_old_graph_id, $_graph_template_id,
|
|
$_skip, $_totali, $_graph_item_sequence, $_selected_graph_index, $_color_templates, $_graph_item_types, $_cdefs,
|
|
$_graph_type, $_gprint_prefix, $_total, $_total_type = '', $member_graphs = array()) {
|
|
|
|
global $struct_graph_item, $graph_item_types, $config;
|
|
|
|
include_once($config['base_path'] . '/lib/api_aggregate.php');
|
|
|
|
/* suppress warnings */
|
|
error_reporting(E_ALL);
|
|
|
|
/* install own error handler */
|
|
set_error_handler('aggregate_error_handler');
|
|
|
|
cacti_log(__FUNCTION__ . ' called. Insert example graph:' . $_old_graph_id . ' Graph Template:' . $_graph_template_id . ' into Graph:' . $_new_graph_id . ' at Sequence:' . $_graph_item_sequence . ' Graph_No:' . $_selected_graph_index . ' Type Action: ' . $_graph_type, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
cacti_log(__FUNCTION__ . ' skipping: ' . serialize($_skip), true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
# take graph item data from old one
|
|
if (!empty($_old_graph_id)) {
|
|
$graph_items = db_fetch_assoc_prepared('SELECT *
|
|
FROM graph_templates_item
|
|
WHERE local_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($_old_graph_id));
|
|
|
|
$graph_local = db_fetch_row_prepared('SELECT host_id, graph_template_id,
|
|
snmp_query_id, snmp_index
|
|
FROM graph_local
|
|
WHERE id = ?',
|
|
array($_old_graph_id));
|
|
} else {
|
|
$graph_items = db_fetch_assoc_prepared('SELECT *
|
|
FROM graph_templates_item
|
|
WHERE local_graph_id = ?
|
|
AND graph_template_id = ?
|
|
ORDER BY sequence',
|
|
array($_old_graph_id, $_graph_template_id));
|
|
|
|
$graph_local = array();
|
|
}
|
|
|
|
/* create new entry(s): graph_templates_item */
|
|
$num_items = sizeof($graph_items);
|
|
if ($num_items > 0) {
|
|
# take care of items having a HR that shall be skipped
|
|
$i = 0;
|
|
for ($i; $i < $num_items; $i++) {
|
|
# remember existing hard returns (array must start at 1 to match $skipped_items
|
|
$_hr[$i+1] = ($graph_items[$i]['hard_return'] != '');
|
|
}
|
|
# move 'skipped hard returns' to previous graph item
|
|
$_hr = auto_hr($_skip, $_hr);
|
|
|
|
# next entry will have to have a prepended text format
|
|
$prepend = true;
|
|
$skip_graph = false;
|
|
$make0_cdef = aggregate_cdef_make0();
|
|
$i = 0;
|
|
|
|
foreach ($graph_items as $graph_item) {
|
|
# loop starts at 0, but $_skip starts at 1, so increment before comparing
|
|
$i++;
|
|
# go ahead, if this graph item has to be skipped
|
|
if (isset($_skip[$i]) && !empty($_skip[$i])) {
|
|
continue;
|
|
}
|
|
|
|
if ($_total == AGGREGATE_TOTAL_ONLY) {
|
|
# if we only need the totalling legend, ...
|
|
if (($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_GPRINT) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_GPRINT_LAST) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_GPRINT_MIN) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_GPRINT_MAX) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_GPRINT_AVERAGE) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_TEXTALIGN) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_TIC) ||
|
|
($graph_item['graph_type_id'] == GRAPH_ITEM_TYPE_COMMENT)) {
|
|
# and this is a legend entry (GPRINT, COMMENT), skip
|
|
continue;
|
|
} else {
|
|
# this is a graph entry, remove text to make it disappear
|
|
# do NOT skip!
|
|
# we need this entry as a DEF
|
|
# and as long as cacti does not provide for a 'pure DEF' graph item type
|
|
# we need this workaround
|
|
$graph_item['text_format'] = '';
|
|
|
|
# make sure, that this entry does not have a HR,
|
|
# else a single colored mark will be drawn
|
|
$graph_item['hard_return'] = '';
|
|
$_hr[$i] = '';
|
|
|
|
# make sure, that data of this item will be suppressed: make 0!
|
|
$graph_item['cdef_id'] = $make0_cdef;
|
|
|
|
# try to pick the best totaling cf id
|
|
$graph_item['consolidation_function_id'] = db_fetch_cell('SELECT DISTINCT consolidation_function_id
|
|
FROM graph_templates_item
|
|
WHERE color_id>0
|
|
AND sequence = ' . $graph_item['sequence'] .
|
|
(sizeof($member_graphs) ? ' AND ' . array_to_sql_or($member_graphs, 'local_graph_id'):'') .
|
|
(sizeof($_skip) ? ' AND sequence NOT IN (' . implode(',', $_skip) . ')':'') .
|
|
(sizeof($_totali) ? ' AND sequence IN (' . implode(',', $_totali) . ')':'') . '
|
|
LIMIT 1');
|
|
}
|
|
}
|
|
|
|
# use all data from 'old' graph ...
|
|
$save = $graph_item;
|
|
|
|
# now it's time for some 'special purpose' processing
|
|
# selected fields will need special treatment
|
|
|
|
# take care of color changes only if not set to None
|
|
if (isset($_color_templates[$i])) {
|
|
if ($_color_templates[$i] > 0) {
|
|
# get the size of the color templates array
|
|
# if number of colored items exceed array size, use round robin
|
|
$num_colors = db_fetch_cell_prepared('SELECT COUNT(color_id)
|
|
FROM color_template_items
|
|
WHERE color_template_id = ?',
|
|
array($_color_templates[$i]));
|
|
|
|
# templating required, get color for current graph item
|
|
$sql = 'SELECT color_id
|
|
FROM color_template_items
|
|
WHERE color_template_id=' . $_color_templates[$i] . '
|
|
ORDER BY sequence
|
|
LIMIT ' . ($_selected_graph_index % $num_colors) . ',1';
|
|
|
|
$save['color_id'] = db_fetch_cell($sql);
|
|
} else {
|
|
/* set a color even if no color templating is required */
|
|
$save['color_id'] = $graph_item['color_id'];
|
|
}
|
|
} /* else: no color templating defined, e.g. GPRINT entry */
|
|
|
|
# do we want to override cdef of this item
|
|
# certanly not if it was set to $make0_cdef above
|
|
if ($_cdefs[$i] > 0 && $graph_item['cdef_id'] != $make0_cdef) {
|
|
$save['cdef_id'] = $_cdefs[$i];
|
|
}
|
|
|
|
# take care of the graph_item_type
|
|
# user may want to override types (ex. LINEx to AREA)
|
|
# do this before we try start converting stuff to AREAs and such
|
|
if ($_graph_item_types[$i] > 0) {
|
|
$save['graph_type_id'] = $_graph_item_types[$i];
|
|
} else {
|
|
$save['graph_type_id'] = $graph_item['graph_type_id'];
|
|
}
|
|
|
|
/* change graph types, if requested */
|
|
$save['graph_type_id'] = aggregate_change_graph_type($_selected_graph_index, $save['graph_type_id'], $_graph_type);
|
|
|
|
# new item text format required?
|
|
if ($prepend && ($_total_type == AGGREGATE_TOTAL_TYPE_ALL)) {
|
|
# pointless to add any data source item name here, cause ALL are totaled
|
|
$save['text_format'] = $_gprint_prefix;
|
|
|
|
# no more prepending until next line break is encountered
|
|
$prepend = false;
|
|
} elseif ($prepend && $save['text_format'] != '' && $_gprint_prefix != '') {
|
|
$save['text_format'] = substitute_host_data($_gprint_prefix . ' ' . $save['text_format'], '|', '|', (isset($graph_local['host_id']) ? $graph_local['host_id']:0));
|
|
cacti_log(__FUNCTION__ . ' substituted:' . $save['text_format'], true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
/* if this is a data query graph type, try to substitute */
|
|
if (isset($graph_local['snmp_query_id']) && $graph_local['snmp_query_id'] > 0 && $graph_local['snmp_index'] != '') {
|
|
$save['text_format'] = substitute_snmp_query_data($save['text_format'], $graph_local['host_id'], $graph_local['snmp_query_id'], $graph_local['snmp_index'], read_config_option('max_data_query_field_length'));
|
|
|
|
cacti_log(__FUNCTION__ . ' substituted:' . $save['text_format'] . ' for ' . $graph_local['host_id'] . ',' . $graph_local['snmp_query_id'] . ',' . $graph_local['snmp_index'], true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
}
|
|
|
|
# no more prepending until next line break is encountered
|
|
$prepend = false;
|
|
}
|
|
|
|
# <HR> wanted?
|
|
if (isset($_hr[$i]) && $_hr[$i] > 0) {
|
|
$save['hard_return'] = 'on';
|
|
}
|
|
# if this item defines a line break, remember to prepend next line
|
|
if ($save['text_format'] != '') {
|
|
$prepend = ($save['hard_return'] == 'on');
|
|
}
|
|
|
|
# provide new sequence number
|
|
$save['sequence'] = $_graph_item_sequence;
|
|
cacti_log(__FUNCTION__ . ' hard return: ' . $save['hard_return'] . ' sequence: ' . $_graph_item_sequence, true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
$save['id'] = 0;
|
|
$save['local_graph_template_item_id'] = 0; # disconnect this graph item from the graph template item
|
|
$save['local_graph_id'] = (isset($_new_graph_id) ? $_new_graph_id : 0);
|
|
$save['graph_template_id'] = 0; # disconnect this graph item from the graph template
|
|
$save['hash'] = ''; # remove any template attribs
|
|
|
|
$graph_item_mappings{$graph_item['id']} = sql_save($save, 'graph_templates_item');
|
|
|
|
$_graph_item_sequence++;
|
|
}
|
|
}
|
|
|
|
/* restore original error handler */
|
|
restore_error_handler();
|
|
|
|
# return with next sequence number to be filled
|
|
return $_graph_item_sequence;
|
|
}
|
|
|
|
/**
|
|
* insert or update aggregate graph items in DB tables
|
|
* @param array $items
|
|
* @param string $table
|
|
* @return bool ture if save was succesfull, false otherwise
|
|
*/
|
|
function aggregate_graph_items_save($items, $table) {
|
|
$defaults = array();
|
|
if ($table == 'aggregate_graphs_graph_item') {
|
|
$defaults['aggregate_graph_id'] = null;
|
|
$id_field = 'aggregate_graph_id';
|
|
} elseif ($table == 'aggregate_graph_templates_item') {
|
|
$defaults['aggregate_template_id'] = null;
|
|
$id_field = 'aggregate_template_id';
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
$defaults['graph_templates_item_id'] = null;
|
|
$defaults['sequence'] = 0;
|
|
$defaults['color_template'] = 0;
|
|
$defaults['t_graph_type_id'] = '';
|
|
$defaults['graph_type_id'] = 0;
|
|
$defaults['t_cdef_id'] = '';
|
|
$defaults['cdef_id'] = 0;
|
|
$defaults['item_skip'] = '';
|
|
$defaults['item_total'] = '';
|
|
|
|
$items_sql = array();
|
|
foreach ($items as $item) {
|
|
// substitute any missing fields with defaults
|
|
$item = array_merge($defaults, $item);
|
|
|
|
// remove any extra fields
|
|
$item = array_intersect_key($item, $defaults);
|
|
|
|
// without these graph item makes no sense
|
|
if (!isset($item[$id_field]) || !isset($item['graph_templates_item_id'])) {
|
|
return false;
|
|
}
|
|
|
|
// convert to partial SQL statement
|
|
$items_sql[] .= sprintf(
|
|
' (%d, %d, %d, %d, %s, %d, %s, %d, %s, %s)',
|
|
$item[$id_field],
|
|
$item['graph_templates_item_id'],
|
|
$item['sequence'],
|
|
$item['color_template'],
|
|
db_qstr($item['t_graph_type_id']),
|
|
$item['graph_type_id'],
|
|
db_qstr($item['t_cdef_id']),
|
|
$item['cdef_id'],
|
|
db_qstr($item['item_skip']),
|
|
db_qstr($item['item_total'])
|
|
);
|
|
}
|
|
|
|
$sql = 'INSERT INTO ' . $table;
|
|
$sql .= '(' . implode(', ', array_keys($defaults)) . ') VALUES ';
|
|
$sql .= implode(', ', $items_sql);
|
|
|
|
cacti_log(__FUNCTION__ . ' called. SQL: ' . $sql, true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
/* remove all old items */
|
|
if (isset( $items[0][$id_field])) {
|
|
db_execute("DELETE FROM $table WHERE " . $id_field . '=' . $items[0][$id_field]);
|
|
}
|
|
|
|
if (db_execute($sql) == 1) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Validate extra graph parameters posted from graph edit form.
|
|
* You can check for validation errors with cacti function is_error_message
|
|
* @param array $posted - values posted from form
|
|
* @param bool $has_override - form had override checkboxes
|
|
* @return array - cleaned up graph parameters
|
|
*/
|
|
function aggregate_validate_graph_params($posted, $has_override = false) {
|
|
$check_post_params = array(
|
|
'image_format_id' => array('type' => 'int', 'allow_empty' => false, 'default' => 0, 'regex' => ''),
|
|
'height' => array('type' => 'int', 'allow_empty' => false, 'default' => 0, 'regex' => '^[0-9]+$'),
|
|
'width' => array('type' => 'int', 'allow_empty' => false, 'default' => 0, 'regex' => '^[0-9]+$'),
|
|
'upper_limit' => array('type' => 'int', 'allow_empty' => true, 'default' => 0, 'regex' => '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U$'),
|
|
'lower_limit' => array('type' => 'int', 'allow_empty' => true, 'default' => 0, 'regex' => '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U$'),
|
|
'vertical_label' => array('type' => 'str', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'slope_mode' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'auto_scale' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'auto_scale_opts' => array('type' => 'int', 'allow_empty' => false, 'default' => 0, 'regex' => ''),
|
|
'auto_scale_log' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'scale_log_units' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'auto_scale_rigid' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'auto_padding' => array('type' => 'bool', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'base_value' => array('type' => 'int', 'allow_empty' => true, 'default' => 0, 'regex' => '^[0-9]+$'),
|
|
'unit_value' => array('type' => 'str', 'allow_empty' => true, 'default' => '', 'regex' => ''),
|
|
'unit_exponent_value' => array('type' => 'int', 'allow_empty' => true, 'default' => '', 'regex' => '^-?[0-9]+$')
|
|
);
|
|
|
|
$params_new = array();
|
|
|
|
/* validate posted form fields */
|
|
foreach ($check_post_params as $field => $defs) {
|
|
if ($has_override && !isset($posted['t_'.$field])) {
|
|
/* override checkbox off - use default value */
|
|
$params_new['t_'.$field] = '';
|
|
$params_new[$field] = $defs['default'];
|
|
continue;
|
|
}
|
|
|
|
if ($has_override) {
|
|
/* override checkbox was on */
|
|
$params_new['t_'.$field] = 'on';
|
|
}
|
|
|
|
/* validate value */
|
|
if ($defs['type'] == 'bool') {
|
|
$params_new[$field] = (isset($posted[$field])) ? 'on' : '';
|
|
} else {
|
|
$params_new[$field] = (isset($posted[$field]) ? form_input_validate(htmlspecialchars($posted[$field]), $field, $defs['regex'], $defs['allow_empty'], 3) : $defs['default']);
|
|
}
|
|
}
|
|
|
|
return $params_new;
|
|
}
|
|
|
|
|
|
/**
|
|
* Populate grraph items array with posted values.
|
|
* $graph_items array must be keyed on graph item id.
|
|
* @param array $posted - values posted from form
|
|
* @param array $graph_items - reference to graph items array to update with form values
|
|
*
|
|
*/
|
|
function aggregate_validate_graph_items($posted, &$graph_items) {
|
|
foreach ($_POST as $var => $val) {
|
|
/* work on color_templates */
|
|
if (preg_match('/^agg_color_([0-9]+)$/', $var, $matches)) {
|
|
/* ================= input validation ================= */
|
|
input_validate_input_number($matches[1]);
|
|
/* ==================================================== */
|
|
$graph_templates_item_id = str_replace('agg_color_', '', $var);
|
|
if (isset($graph_items[$graph_templates_item_id])) {
|
|
$graph_items[$graph_templates_item_id]['color_template'] = $val;
|
|
} else {
|
|
cacti_log('Something fubar in agg_color');
|
|
}
|
|
}
|
|
|
|
/* work on checkboxed for skipping items */
|
|
if (preg_match('/^agg_skip_([0-9]+)$/', $var, $matches)) {
|
|
/* ================= input validation ================= */
|
|
input_validate_input_number($matches[1]);
|
|
/* ==================================================== */
|
|
$graph_templates_item_id = str_replace('agg_skip_', '', $var);
|
|
if (isset($graph_items[$graph_templates_item_id])) {
|
|
$graph_items[$graph_templates_item_id]['item_skip'] = $val;
|
|
} else {
|
|
cacti_log('Something fubar in agg_skip');
|
|
}
|
|
}
|
|
|
|
/* work on checkboxed for totalling items */
|
|
if (preg_match('/^agg_total_([0-9]+)$/', $var, $matches)) {
|
|
/* ================= input validation ================= */
|
|
input_validate_input_number($matches[1]);
|
|
/* ==================================================== */
|
|
$graph_templates_item_id = str_replace('agg_total_', '', $var);
|
|
if (isset($graph_items[$graph_templates_item_id])) {
|
|
$graph_items[$graph_templates_item_id]['item_total'] = $val;
|
|
} else {
|
|
cacti_log('Something fubar in agg_total');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* cleanup of graph items of the new graph
|
|
* @param int $base - base graph id
|
|
* @param int $aggregate - graph id of aggregate
|
|
* @param int $reorder - type of reordering
|
|
*/
|
|
function aggregate_graphs_cleanup($base, $aggregate, $reorder) {
|
|
global $config;
|
|
|
|
include_once($config['base_path'] . '/lib/api_aggregate.php');
|
|
|
|
cacti_log(__FUNCTION__ . ' called. Base ' . $base . ' Aggregate ' . $aggregate . ' Reorder: ' . $reorder, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* suppress warnings */
|
|
error_reporting(E_ALL);
|
|
|
|
/* install own error handler */
|
|
set_error_handler('aggregate_error_handler');
|
|
|
|
/* restore original error handler */
|
|
restore_error_handler();
|
|
}
|
|
|
|
/**
|
|
* reorder graph items
|
|
* @param int $base - base graph id
|
|
* @param int $aggregate - graph id of aggregate
|
|
* @param int $reorder - type of reordering
|
|
*/
|
|
function aggregate_reorder_ds_graph($base, $graph_template_id, $aggregate, $reorder) {
|
|
global $config;
|
|
|
|
include_once($config['base_path'] . '/lib/api_aggregate.php');
|
|
|
|
cacti_log(__FUNCTION__ . ' called. Base Graph ' . $base . ' Graph Template ' . $graph_template_id . ' Aggregate Graph ' . $aggregate . ' Reorder: ' . $reorder, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* suppress warnings */
|
|
error_reporting(E_ALL);
|
|
|
|
/* install own error handler */
|
|
set_error_handler('aggregate_error_handler');
|
|
|
|
if ($reorder == AGGREGATE_ORDER_DS_GRAPH) {
|
|
$new_seq = 1;
|
|
|
|
/* get all different local_data_template_rrd_id's
|
|
* respecting the order that the aggregated graph has
|
|
*/
|
|
$sql_where = "WHERE gti.local_graph_id=$base" . ($base == 0 ? " AND gti.graph_template_id=$graph_template_id":'');
|
|
$sql_id_column = ($base == 0 ? 'id': 'local_data_template_rrd_id');
|
|
$sql = "SELECT DISTINCT dtr.$sql_id_column AS local_data_template_rrd_id
|
|
FROM data_template_rrd AS dtr
|
|
LEFT JOIN graph_templates_item AS gti
|
|
ON (gti.task_item_id=dtr.id)
|
|
$sql_where
|
|
ORDER BY gti.sequence";
|
|
|
|
$ds_ids = db_fetch_assoc($sql);
|
|
|
|
foreach($ds_ids as $ds_id) {
|
|
cacti_log('local_data_template_rrd_id: ' . $ds_id['local_data_template_rrd_id'], false, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
/* get all different task_item_id's
|
|
* respecting the order that the aggregated graph has
|
|
*/
|
|
$sql = "SELECT gti.id, gti.task_item_id
|
|
FROM graph_templates_item AS gti
|
|
LEFT JOIN data_template_rrd AS dtr
|
|
ON (gti.task_item_id=dtr.id)
|
|
WHERE gti.local_graph_id=$aggregate
|
|
AND dtr.local_data_template_rrd_id=" . $ds_id['local_data_template_rrd_id'] . "
|
|
ORDER BY sequence";
|
|
|
|
cacti_log(__FUNCTION__ . ' sql: ' . $sql, false, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
$items = db_fetch_assoc($sql);
|
|
|
|
foreach($items as $item) {
|
|
# accumulate the updates to avoid interfering the next loops
|
|
$updates[] = 'UPDATE graph_templates_item SET sequence=' . $new_seq++ . ' WHERE id=' . $item['id'];
|
|
}
|
|
}
|
|
|
|
# now get all 'empty' local_data_template_rrd_id's
|
|
# = those graph items without associated data source (e.g. COMMENT)
|
|
$sql = "SELECT id
|
|
FROM graph_templates_item AS gti
|
|
WHERE gti.local_graph_id=$aggregate
|
|
AND gti.task_item_id=0
|
|
ORDER BY sequence";
|
|
|
|
cacti_log($sql, false, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
$empty_task_items = db_fetch_assoc($sql);
|
|
|
|
# now add those 'empty' one's to the end
|
|
foreach($empty_task_items as $item) {
|
|
# accumulate the updates to avoid interfering the next loops
|
|
$updates[] = 'UPDATE graph_templates_item SET sequence=' . $new_seq++ . ' WHERE id=' . $item['id'];
|
|
}
|
|
|
|
# now run all updates
|
|
if (sizeof($updates)) {
|
|
foreach($updates as $update) {
|
|
cacti_log(__FUNCTION__ . ' update: ' . $update, false, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
db_execute($update);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* restore original error handler */
|
|
restore_error_handler();
|
|
}
|
|
|
|
/**
|
|
* push_out_aggregates - update all aggregates based upon the template
|
|
* @param int aggregate_template_id - the aggregate template id
|
|
* @param int local_graph_id - the specific aggregate graph to update
|
|
* */
|
|
function push_out_aggregates($aggregate_template_id, $local_graph_id = 0) {
|
|
$attribs = array();
|
|
$attribs['skipped_items'] = array();
|
|
$attribs['total_items'] = array();
|
|
$attribs['color_templates'] = array();
|
|
$attribs['graph_item_types']= array();
|
|
$attribs['cdefs'] = array();
|
|
$member_graphs = array();
|
|
|
|
if ($local_graph_id > 0 && $aggregate_template_id == 0) {
|
|
$id = db_fetch_cell_prepared('SELECT id
|
|
FROM aggregate_graphs
|
|
WHERE local_graph_id = ?',
|
|
array($local_graph_id));
|
|
|
|
$attribs['graph_title'] = db_fetch_cell_prepared('SELECT title_format
|
|
FROM aggregate_graphs
|
|
WHERE id = ?',
|
|
array($id));
|
|
|
|
$attribs['skipped_items'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE item_skip="on"
|
|
AND aggregate_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($id)),
|
|
'sequence', 'sequence'
|
|
);
|
|
|
|
$attribs['total_items'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE item_total="on"
|
|
AND aggregate_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($id)),
|
|
'sequence', 'sequence'
|
|
);
|
|
|
|
$attribs['color_templates'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, color_template
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE color_template>=0
|
|
AND aggregate_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($id)),
|
|
'sequence', 'color_template'
|
|
);
|
|
|
|
$attribs['graph_item_types'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, graph_type_id
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE t_graph_type_id="on"
|
|
AND aggregate_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($id)),
|
|
'sequence', 'graph_type_id'
|
|
);
|
|
|
|
$attribs['cdefs'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, cdef_id
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE t_cdef_id="on"
|
|
AND aggregate_graph_id = ?
|
|
ORDER BY sequence',
|
|
array($id)),
|
|
'sequence', 'cdef_id'
|
|
);
|
|
|
|
$attribs['aggregate_graph_id'] = $aggregate_template_id;
|
|
$attribs['template_propogation'] = '';
|
|
|
|
$template_data = db_fetch_row_prepared('SELECT * FROM aggregate_graphs WHERE id = ?', array($id));
|
|
$attribs['graph_template_id'] = $template_data['graph_template_id'];
|
|
$attribs['gprint_prefix'] = $template_data['gprint_prefix'];
|
|
$attribs['graph_type'] = $template_data['graph_type'];
|
|
$attribs['total'] = $template_data['total'];
|
|
$attribs['total_type'] = $template_data['total_type'];
|
|
$attribs['total_prefix'] = $template_data['total_prefix'];
|
|
$attribs['reorder'] = $template_data['order_type'];
|
|
$attribs['item_no'] = db_fetch_cell_prepared('SELECT COUNT(*) FROM aggregate_graphs_graph_item WHERE aggregate_graph_id = ?', array($id));
|
|
} else {
|
|
$attribs['graph_title'] = '';
|
|
|
|
$attribs['skipped_items'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence
|
|
FROM aggregate_graph_templates_item
|
|
WHERE item_skip="on"
|
|
AND aggregate_template_id = ?
|
|
ORDER BY sequence',
|
|
array($aggregate_template_id)),
|
|
'sequence', 'sequence'
|
|
);
|
|
|
|
$attribs['total_items'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence
|
|
FROM aggregate_graph_templates_item
|
|
WHERE item_total="on"
|
|
AND aggregate_template_id = ?
|
|
ORDER BY sequence',
|
|
array($aggregate_template_id)),
|
|
'sequence', 'sequence'
|
|
);
|
|
|
|
$attribs['color_templates'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, color_template
|
|
FROM aggregate_graph_templates_item
|
|
WHERE color_template>=0
|
|
AND aggregate_template_id = ?
|
|
ORDER BY sequence',
|
|
array($aggregate_template_id)),
|
|
'sequence', 'color_template'
|
|
);
|
|
|
|
$attribs['graph_item_types'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, graph_type_id
|
|
FROM aggregate_graph_templates_item
|
|
WHERE t_graph_type_id="on"
|
|
AND aggregate_template_id = ?
|
|
ORDER BY sequence',
|
|
array($aggregate_template_id)),
|
|
'sequence', 'graph_type_id'
|
|
);
|
|
|
|
$attribs['cdefs'] = array_rekey(
|
|
db_fetch_assoc_prepared('SELECT sequence, cdef_id
|
|
FROM aggregate_graph_templates_item
|
|
WHERE t_cdef_id="on"
|
|
AND aggregate_template_id = ?
|
|
ORDER BY sequence',
|
|
array($aggregate_template_id)),
|
|
'sequence', 'cdef_id'
|
|
);
|
|
|
|
$attribs['aggregate_template_id'] = $aggregate_template_id;
|
|
|
|
$template_data = db_fetch_row_prepared("SELECT *
|
|
FROM aggregate_graph_templates
|
|
WHERE id = ?",
|
|
array($aggregate_template_id));
|
|
|
|
$attribs['template_propogation'] = 'on';
|
|
$attribs['graph_template_id'] = $template_data['graph_template_id'];
|
|
$attribs['gprint_prefix'] = $template_data['gprint_prefix'];
|
|
$attribs['graph_type'] = $template_data['graph_type'];
|
|
$attribs['total'] = $template_data['total'];
|
|
$attribs['total_type'] = $template_data['total_type'];
|
|
$attribs['total_prefix'] = $template_data['total_prefix'];
|
|
$attribs['reorder'] = $template_data['order_type'];
|
|
|
|
$attribs['item_no'] = db_fetch_cell_prepared('SELECT COUNT(*)
|
|
FROM aggregate_graph_templates_item
|
|
WHERE aggregate_template_id = ?',
|
|
array($aggregate_template_id));
|
|
}
|
|
|
|
$aggregate_graphs = array();
|
|
if ($local_graph_id > 0) {
|
|
$aggregate_graphs[] = $local_graph_id;
|
|
} else {
|
|
$graphs = db_fetch_assoc_prepared('SELECT local_graph_id
|
|
FROM aggregate_graphs
|
|
WHERE aggregate_template_id = ?',
|
|
array($aggregate_template_id));
|
|
|
|
if (sizeof($graphs)) {
|
|
foreach($graphs as $g) {
|
|
$aggregate_graphs[] = $g['local_graph_id'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sizeof($aggregate_graphs)) {
|
|
foreach($aggregate_graphs as $ag) {
|
|
$member_graphs = array();
|
|
$graphs = db_fetch_assoc_prepared('SELECT DISTINCT agi.local_graph_id
|
|
FROM aggregate_graphs AS ag
|
|
INNER JOIN aggregate_graphs_items AS agi
|
|
ON ag.id=agi.aggregate_graph_id
|
|
WHERE ag.local_graph_id = ?',
|
|
array($ag));
|
|
|
|
/* remove all old graph items first */
|
|
if ($ag > 0) {
|
|
db_execute_prepared('DELETE FROM graph_templates_item
|
|
WHERE local_graph_id = ?',
|
|
array($ag));
|
|
}
|
|
|
|
if (sizeof($graphs)) {
|
|
foreach($graphs as $mg) {
|
|
$member_graphs[] = $mg['local_graph_id'];
|
|
}
|
|
|
|
aggregate_create_update($ag, $member_graphs, $attribs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* aggregate_create_update - either create or update an aggregate based on criteria
|
|
* @param int $local_graph_id - the local graph id of the existing graph. 0 if one needs to be created
|
|
* @param array $member_graphs - the graphs that will be included in this aggregate
|
|
* @return array $attribs - the attributes for this new graph
|
|
* */
|
|
function aggregate_create_update(&$local_graph_id, $member_graphs, $attribs) {
|
|
global $config;
|
|
|
|
include_once($config['base_path'] . '/lib/api_aggregate.php');
|
|
|
|
cacti_log(__FUNCTION__ . ' called. Grapg id: ' . $local_graph_id, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
/* suppress warnings */
|
|
error_reporting(E_ALL);
|
|
|
|
/* install own error handler */
|
|
set_error_handler('aggregate_error_handler');
|
|
|
|
if (sizeof($member_graphs)) {
|
|
$graph_title = (isset($attribs['graph_title']) ? $attribs['graph_title']:'');
|
|
$aggregate_template = (isset($attribs['aggregate_template_id']) ? $attribs['aggregate_template_id']:0);
|
|
$graph_template_id = (isset($attribs['graph_template_id']) ? $attribs['graph_template_id']:0);
|
|
$aggregate_graph = (isset($attribs['aggregate_graph_id']) ? $attribs['aggregate_graph_id']:0);
|
|
$template_propogation = (isset($attribs['template_propogation']) ? $attribs['template_propogation']:'on');
|
|
$gprint_prefix = (isset($attribs['gprint_prefix']) ? $attribs['gprint_prefix']:'');
|
|
$_graph_type = (isset($attribs['graph_type']) ? $attribs['graph_type']:0);
|
|
$_total = (isset($attribs['total']) ? $attribs['total']:0);
|
|
$_total_type = (isset($attribs['total_type']) ? $attribs['total_type']:0);
|
|
$_total_prefix = (isset($attribs['total_prefix']) ? $attribs['total_prefix']:'');
|
|
$_reorder = (isset($attribs['reorder']) ? $attribs['reorder']:0);
|
|
$item_no = (isset($attribs['item_no']) ? $attribs['item_no']:0);
|
|
$color_templates = (is_array($attribs['color_templates']) ? $attribs['color_templates']:array());
|
|
$graph_item_types = (is_array($attribs['graph_item_types']) ? $attribs['graph_item_types']:array());
|
|
$cdefs = (is_array($attribs['cdefs']) ? $attribs['cdefs']:array());
|
|
$skipped_items = (is_array($attribs['skipped_items']) ? $attribs['skipped_items']:array());
|
|
$total_items = (is_array($attribs['total_items']) ? $attribs['total_items']:array());
|
|
$example_graph_id = 0;
|
|
|
|
/* save the aggregate information */
|
|
$save1 = array();
|
|
if ($local_graph_id == 0) {
|
|
# create new graph based on first graph selected
|
|
$local_graph_id = aggregate_graph_save($example_graph_id, $graph_template_id, $graph_title, $aggregate_template);
|
|
$save1['id'] = '';
|
|
$new_aggregate = true;
|
|
} else {
|
|
# update graph params of existing aggregate graph
|
|
$local_graph_id = aggregate_graph_save($local_graph_id, $graph_template_id, $graph_title, $aggregate_template);
|
|
|
|
$save1['id'] = db_fetch_cell_prepared('SELECT id
|
|
FROM aggregate_graphs
|
|
WHERE local_graph_id = ?',
|
|
array($local_graph_id));
|
|
|
|
$new_aggregate = false;
|
|
}
|
|
|
|
$save1['aggregate_template_id'] = $aggregate_template;
|
|
$save1['template_propogation'] = $template_propogation;
|
|
|
|
if (isset($graph_title)) {
|
|
$save1['title_format'] = $graph_title;
|
|
}
|
|
|
|
$save1['local_graph_id'] = $local_graph_id;
|
|
$save1['graph_template_id'] = $graph_template_id;
|
|
$save1['gprint_prefix'] = $gprint_prefix;
|
|
$save1['graph_type'] = $_graph_type;
|
|
$save1['total'] = $_total;
|
|
$save1['total_type'] = $_total_type;
|
|
$save1['total_prefix'] = $_total_prefix;
|
|
$save1['order_type'] = $_reorder;
|
|
$save1['user_id'] = $_SESSION['sess_user_id'];
|
|
$aggregate_graph_id = sql_save($save1, 'aggregate_graphs');
|
|
|
|
# sequence number of next graph item to be added, index starts at 1
|
|
$next_item_sequence = 1;
|
|
$j = 1; $i = 0;
|
|
|
|
/* remove all old graph items first */
|
|
if ($local_graph_id > 0) {
|
|
db_execute_prepared('DELETE FROM graph_templates_item
|
|
WHERE local_graph_id = ?',
|
|
array($local_graph_id));
|
|
}
|
|
|
|
/* now add the graphs one by one to the newly created graph
|
|
* program flow is governed by
|
|
* - totalling
|
|
* - new graph type: convert graph to e.g. AREA
|
|
*/
|
|
# loop for all selected graphs
|
|
foreach ($member_graphs as $graph_id) {
|
|
# insert all graph items of selected graph
|
|
# next items to be inserted have to be in sequence
|
|
$next_item_sequence = aggregate_graphs_insert_graph_items(
|
|
$local_graph_id,
|
|
$graph_id,
|
|
$graph_template_id,
|
|
$skipped_items,
|
|
$total_items,
|
|
$next_item_sequence,
|
|
$i,
|
|
$color_templates,
|
|
$graph_item_types,
|
|
$cdefs,
|
|
$_graph_type,
|
|
$gprint_prefix,
|
|
$_total,
|
|
'',
|
|
$member_graphs);
|
|
|
|
db_execute_prepared('REPLACE INTO aggregate_graphs_items
|
|
(aggregate_graph_id, local_graph_id, sequence)
|
|
VALUES (?, ?, ?)',
|
|
array($aggregate_graph_id, $graph_id, $j));
|
|
|
|
$j++; $i++;
|
|
}
|
|
|
|
cacti_log(__FUNCTION__ . ' all items inserted, next item seq: ' . $next_item_sequence . ' selGraph: ' . $i, true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
/* post processing for pure LINEx graphs
|
|
* if we convert to AREA/STACK, the function aggregate_graphs_insert_graph_items
|
|
* created a pure STACK graph (see comments in that function)
|
|
* so let's find out, if we have a pure STACK now ...
|
|
*/
|
|
if (aggregate_is_pure_stacked_graph($local_graph_id)) {
|
|
/* ... and convert to AREA */
|
|
aggregate_conditional_convert_graph_type($local_graph_id, GRAPH_ITEM_TYPE_STACK, GRAPH_ITEM_TYPE_AREA);
|
|
}
|
|
|
|
if (aggregate_is_stacked_graph($local_graph_id)) {
|
|
/* reorder graph items, if requested
|
|
* for STACKed graphs, reorder before adding totals */
|
|
aggregate_reorder_ds_graph(
|
|
$example_graph_id,
|
|
$graph_template_id,
|
|
$local_graph_id,
|
|
$_reorder);
|
|
}
|
|
|
|
/* special code to add totalling graph items */
|
|
switch ($_total) {
|
|
case AGGREGATE_TOTAL_NONE: # no totalling
|
|
# do NOT add any totalling items
|
|
|
|
break;
|
|
case AGGREGATE_TOTAL_ALL: # any totalling option was selected ...
|
|
$_graph_type = GRAPH_ITEM_TYPE_LINE1;
|
|
|
|
$cf_id = db_fetch_cell('SELECT consolidation_function_id
|
|
FROM graph_templates_item
|
|
WHERE color_id>0' .
|
|
(sizeof($member_graphs) ? ' AND ' . array_to_sql_or($member_graphs, 'local_graph_id'):'') .
|
|
(sizeof($skipped_items) ? ' AND local_graph_id NOT IN(' . implode(',', $skipped_items) . ')':'') . '
|
|
LIMIT 1');
|
|
|
|
/* add an empty line before total items */
|
|
db_execute_prepared("INSERT INTO graph_templates_item
|
|
(local_graph_id, graph_type_id, consolidation_function_id, text_format, value, hard_return, gprint_id, sequence)
|
|
VALUES (?, ?, 1, '', '', 'on', 2, ?)", array($local_graph_id, $cf_id, $next_item_sequence++));
|
|
|
|
case AGGREGATE_TOTAL_ONLY:
|
|
# use the prefix for totalling GPRINTs as given by the user
|
|
switch ($_total_type) {
|
|
case AGGREGATE_TOTAL_TYPE_SIMILAR:
|
|
case AGGREGATE_TOTAL_TYPE_ALL:
|
|
$gprint_prefix = $_total_prefix;
|
|
break;
|
|
}
|
|
|
|
# now skip all items, that are
|
|
# - explicitely marked as skipped (based on $skipped_items)
|
|
# - OR NOT marked as 'totalling' items
|
|
for ($k=1; $k<=$item_no; $k++) {
|
|
cacti_log(__FUNCTION__ . ' old skip: ' . (isset($skipped_items[$k]) ? $skipped_items[$k]:''), true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
|
|
# skip all items, that shall not be totalled
|
|
if (!isset($total_items[$k])) $skipped_items[$k] = $k;
|
|
|
|
cacti_log(__FUNCTION__ . ' new skip: ' . (isset($skipped_items[$k]) ? $skipped_items[$k]:''), true, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
|
}
|
|
|
|
# add the 'templating' graph to the new graph, honoring skipped, hr and color
|
|
$foo = aggregate_graphs_insert_graph_items(
|
|
$local_graph_id,
|
|
$example_graph_id,
|
|
$graph_template_id,
|
|
$skipped_items,
|
|
$total_items,
|
|
$next_item_sequence,
|
|
$i,
|
|
$color_templates,
|
|
$graph_item_types,
|
|
$cdefs,
|
|
$_graph_type, #TODO: user may choose LINEx instead of assuming LINE1
|
|
$gprint_prefix,
|
|
AGGREGATE_TOTAL_ALL, # now add the totalling line(s)
|
|
$_total_type,
|
|
$member_graphs);
|
|
|
|
# now pay attention to CDEFs
|
|
# next_item_sequence still points to the first totalling graph item
|
|
aggregate_cdef_totalling(
|
|
$local_graph_id,
|
|
$next_item_sequence,
|
|
$_total_type);
|
|
}
|
|
|
|
/* post processing for pure LINEx graphs
|
|
* if we convert to AREA/STACK, the function aggregate_graphs_insert_graph_items
|
|
* created a pure STACK graph (see comments in that function)
|
|
* so let's find out, if we have a pure STACK now ...
|
|
*/
|
|
if (aggregate_is_pure_stacked_graph($local_graph_id)) {
|
|
/* ... and convert to AREA */
|
|
aggregate_conditional_convert_graph_type($local_graph_id, GRAPH_ITEM_TYPE_STACK, GRAPH_ITEM_TYPE_AREA);
|
|
}
|
|
|
|
if (!aggregate_is_stacked_graph($local_graph_id)) {
|
|
/* reorder graph items, if requested
|
|
* for non-STACKed graphs, we want to reorder the totals as well */
|
|
aggregate_reorder_ds_graph(
|
|
$example_graph_id,
|
|
$graph_template_id,
|
|
$local_graph_id,
|
|
$_reorder);
|
|
}
|
|
}
|
|
|
|
/* restore original error handler */
|
|
restore_error_handler();
|
|
}
|
|
|
|
function aggregate_get_data_sources(&$graph_array, &$data_sources, &$graph_template) {
|
|
/* find out which (if any) data sources are being used by this graph, so we can tell the user */
|
|
if (isset($graph_array)) {
|
|
# fetch all data sources for all selected graphs
|
|
$data_sources = db_fetch_assoc('SELECT
|
|
data_template_data.local_data_id,
|
|
data_template_data.name_cache
|
|
FROM (data_template_rrd,data_template_data,graph_templates_item)
|
|
WHERE graph_templates_item.task_item_id=data_template_rrd.id
|
|
AND data_template_rrd.local_data_id=data_template_data.local_data_id
|
|
AND ' . array_to_sql_or($graph_array, 'graph_templates_item.local_graph_id') . '
|
|
AND data_template_data.local_data_id>0
|
|
GROUP BY data_template_data.local_data_id
|
|
ORDER BY data_template_data.name_cache');
|
|
|
|
# verify, that only a single graph template is used, else
|
|
# aggregate will look funny
|
|
$sql = 'SELECT DISTINCT graph_templates.id, graph_templates.name
|
|
FROM graph_local
|
|
LEFT JOIN graph_templates ON (graph_local.graph_template_id=graph_templates.id)
|
|
WHERE (' . array_to_sql_or($graph_array, 'graph_local.id') . ')
|
|
AND graph_local.graph_template_id>0';
|
|
$used_graph_templates = db_fetch_assoc($sql);
|
|
|
|
if (sizeof($used_graph_templates) > 1) {
|
|
# this is invalid! STOP
|
|
print "<tr><td colspan='2' class='textArea'>
|
|
<p>" . __('The Graphs chosen for the Aggregate Graph below represent Graphs from multiple Graph Templates. Aggregate does not support creating Aggregate Graphs from multiple Graph Templates.') . "</p>";
|
|
print "<p>" . __('Press \'Return\' to return and select different Graphs') . "</p>\n";
|
|
print "<ul>";
|
|
foreach ($used_graph_templates as $graph_template) {
|
|
print '<li>' . htmlspecialchars($graph_template['name'], ENT_QUOTES) . "</li>\n";
|
|
}
|
|
print '</ul></td></tr>';
|
|
|
|
?>
|
|
<script type='text/javascript'>
|
|
$().ready(function() {
|
|
$('#continue').hide();
|
|
$('#cancel').attr('value', 'Return');
|
|
});
|
|
</script>
|
|
<?php
|
|
} elseif (sizeof($used_graph_templates) < 1) {
|
|
/* selected graphs do not use templates */
|
|
print "<tr><td colspan='2' class='textArea'>
|
|
<p>" . __('The Graphs chosen for the Aggregate Graph do not use Graph Templates. Aggregate does not support creating Aggregate Graphs from non-templated graphs.') . "</p>";
|
|
print "<p>" . __('Press \'Return\' to return and select different Graphs') . "</p>\n";
|
|
print '</td></tr>';
|
|
|
|
?>
|
|
<script type='text/javascript'>
|
|
$(function() {
|
|
$('#continue').hide();
|
|
$('#cancel').attr('value', 'Return');
|
|
});
|
|
</script>
|
|
<?php
|
|
} else {
|
|
$graph_template = $used_graph_templates[0]['id'];
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* draw_aggregate_template_graph_items_list - draw graph item list
|
|
*
|
|
* @param int $_graph_template_id - id of the graph for which the items shall be listed
|
|
# @param int $_object - either the aggregate or aggregate_template
|
|
*/
|
|
function draw_aggregate_graph_items_list($_graph_id = 0, $_graph_template_id = 0, $_object = array()) {
|
|
global $config;
|
|
|
|
include($config['include_path'] . '/global_arrays.php');
|
|
|
|
cacti_log(__FUNCTION__ . ' called. graph: ' . $_graph_id . ' template: ' . $_graph_template_id, true, 'AGGREGATE', POLLER_VERBOSITY_DEVDBG);
|
|
|
|
if ($_graph_id == 0 && $_graph_template_id == 0) {
|
|
return null;
|
|
}
|
|
|
|
/* fetch graph items */
|
|
if ($_graph_id == 0) {
|
|
$item_list_where = "gti.local_graph_id=0 AND graph_template_id=$_graph_template_id ";
|
|
}
|
|
if ($_graph_template_id == 0) {
|
|
$item_list_where = "gti.local_graph_id=$_graph_id ";
|
|
}
|
|
$item_list = db_fetch_assoc("SELECT
|
|
gti.id, gti.text_format, gti.value, gti.hard_return, gti.graph_type_id,
|
|
gti.consolidation_function_id, cdef.name as cdef_name, colors.hex
|
|
FROM graph_templates_item AS gti
|
|
LEFT JOIN cdef ON (gti.cdef_id=cdef.id)
|
|
LEFT JOIN colors ON (gti.color_id=colors.id)
|
|
WHERE $item_list_where
|
|
ORDER BY gti.sequence");
|
|
|
|
/* fetch color templates */
|
|
$color_templates = db_fetch_assoc('SELECT color_template_id, name FROM color_templates ORDER BY name');
|
|
|
|
$current_vals = array();
|
|
$is_edit = false;
|
|
$is_templated = false;
|
|
if (sizeof($_object) > 0 && $_object['id'] > 0) {
|
|
/* drawing items for existing aggregate graph/template */
|
|
$is_edit =true;
|
|
/* fetch existing item values */
|
|
if (isset($_object['aggregate_template_id']) && $_object['aggregate_template_id'] == 0) {
|
|
/* this is aggregate graph with no aggregate template */
|
|
$current_vals = db_fetch_assoc_prepared('SELECT *
|
|
FROM aggregate_graphs_graph_item
|
|
WHERE aggregate_graph_id = ?',
|
|
array($_object['id']));
|
|
|
|
$item_editor_link_param = 'aggregate_graph_id='.$_object['id'].'&local_graph_id='.$_object['local_graph_id'];
|
|
$is_templated = false;
|
|
} elseif (isset($_object['aggregate_template_id'])) {
|
|
/* this is aggregate graph from aggregate template */
|
|
$current_vals = db_fetch_assoc_prepared('SELECT *
|
|
FROM aggregate_graph_templates_item
|
|
WHERE aggregate_template_id = ?',
|
|
array($_object['aggregate_template_id']));
|
|
|
|
$item_editor_link_param = 'aggregate_template_id='.$_object['aggregate_template_id'];
|
|
$is_templated = true;
|
|
} else {
|
|
/* this is aggregate template */
|
|
$current_vals = db_fetch_assoc_prepared('SELECT *
|
|
FROM aggregate_graph_templates_item
|
|
WHERE aggregate_template_id = ?',
|
|
array($_object['id']));
|
|
|
|
$item_editor_link_param = 'aggregate_template_id='.$_object['id'];
|
|
$is_templated = true;
|
|
}
|
|
/* key results on item id */
|
|
$current_vals = array_rekey(
|
|
$current_vals,
|
|
'graph_templates_item_id',
|
|
array('color_template', 'item_skip', 'item_total', 't_graph_type_id', 'graph_type_id')
|
|
);
|
|
}
|
|
|
|
# draw list of graph items
|
|
html_start_box(($is_templated ? __('Graph Template Items'):__('Graph Items')), '100%', '', '3', 'center', '');
|
|
|
|
# print column header
|
|
print "<tr class='tableHeader'>\n";
|
|
DrawMatrixHeaderItem(__('Graph Item'), '', 1);
|
|
DrawMatrixHeaderItem(__('Data Source'), '',1);
|
|
DrawMatrixHeaderItem(__('Graph Item Type'), '', 1);
|
|
DrawMatrixHeaderItem(__('CF Type'), '', 1);
|
|
DrawMatrixHeaderItem(__('Item Color'), '', 2);
|
|
DrawMatrixHeaderItem(__('Color Template'), '', 1);
|
|
DrawMatrixHeaderItem(__('Skip'), '', 1);
|
|
DrawMatrixHeaderItem(__('Total'), '', 1);
|
|
print '</tr>';
|
|
|
|
$group_counter = 0; $_graph_type_name = ''; $i = 0;
|
|
|
|
if (sizeof($item_list)) {
|
|
foreach ($item_list as $item) {
|
|
/* graph grouping display logic */
|
|
$this_row_style = '';
|
|
$use_custom_class = false;
|
|
$hard_return = '';
|
|
|
|
if (!preg_match('/(GPRINT|TEXTALIGN|HRULE|VRULE|TICK)/', $graph_item_types[$item['graph_type_id']])) {
|
|
$this_row_style = 'font-weight: bold;';
|
|
$use_custom_class = true;
|
|
|
|
if ($group_counter % 2 == 0) {
|
|
$customClass = 'graphItem';
|
|
} else {
|
|
$customClass = 'graphItemAlternate';
|
|
}
|
|
|
|
$group_counter++;
|
|
}
|
|
|
|
/* column "Data Source" */
|
|
$_graph_type_name = $graph_item_types[$item['graph_type_id']];
|
|
$force_skip = false;
|
|
|
|
switch (true) {
|
|
case preg_match('/(TEXTALIGN)/', $_graph_type_name):
|
|
$matrix_title = 'TEXTALIGN: ' . ucfirst($item['textalign']);
|
|
break;
|
|
case preg_match('/(TICK)/', $_graph_type_name):
|
|
$matrix_title = '(' . $item['data_source_name'] . '): ' . $item['text_format'];
|
|
break;
|
|
case preg_match('/(AREA|STACK|GPRINT|LINE[123])/', $_graph_type_name):
|
|
$matrix_title = $item['text_format'];
|
|
break;
|
|
case preg_match('/(HRULE)/', $_graph_type_name):
|
|
$force_skip = true;
|
|
$matrix_title = 'HRULE: ' . $item['value'];
|
|
break;
|
|
case preg_match('/(VRULE)/', $_graph_type_name):
|
|
$force_skip = true;
|
|
$matrix_title = 'VRULE: ' . $item['value'];
|
|
break;
|
|
case preg_match('/(COMMENT)/', $_graph_type_name):
|
|
$force_skip = true;
|
|
$matrix_title = 'COMMENT: ' . $item['text_format'];
|
|
break;
|
|
}
|
|
|
|
/* values can be overriden in aggregate graph/template */
|
|
if ($is_edit && isset($current_vals[$item['id']]['t_graph_type_id']) && $current_vals[$item['id']]['t_graph_type_id'] == 'on') {
|
|
$item['graph_type_id'] = $current_vals[$item['id']]['graph_type_id'];
|
|
}
|
|
|
|
/* alternating row color */
|
|
if ($use_custom_class == false) {
|
|
form_alternate_row();
|
|
} else {
|
|
print "<tr class='$customClass'>";
|
|
}
|
|
|
|
/* column 'Graph Item' */
|
|
print '<td title="' . __esc('Aggregate Items are not modifyable') . '">';
|
|
if ($is_edit == false) {
|
|
/* no existing aggregate graph/template */
|
|
print __('Item # %d', ($i+1));
|
|
} elseif (isset($_object['template_propogation']) && $_object['template_propogation']) {
|
|
/* existing aggregate graph with template propagation enabled */
|
|
print __('Item # %d', ($i+1));
|
|
} else {
|
|
/* existing aggregate template or graph with no templating */
|
|
/* create a link to graph item editor */
|
|
//print '<a class="pic" href="aggregate_items.php?action=item_edit&'.$item_editor_link_param.'&id='.$item['id'].'">' . __('Item # %d', ($i+1)) . '</a>';
|
|
print '<a title="' . __esc('Aggregate Items are not editable') . '" class="pic" href="#">' . __('Item # %d', ($i+1)) . '</a>';
|
|
}
|
|
print "</td>\n";
|
|
|
|
if ($item['hard_return'] == 'on') {
|
|
$hard_return = '<strong><span style="color:#FF0000;"><HR></span></strong>';
|
|
}
|
|
|
|
print "<td style='$this_row_style'>" . htmlspecialchars($matrix_title) . $hard_return . "</td>\n";
|
|
|
|
/* column 'Graph Item Type' */
|
|
print "<td style='$this_row_style'>" . $graph_item_types{$item['graph_type_id']} . "</td>\n";
|
|
|
|
/* column 'CF Type' */
|
|
print "<td style='$this_row_style'>" . $consolidation_functions{$item['consolidation_function_id']} . "</td>\n";
|
|
|
|
/* column 'Item Color' */
|
|
print "<td style='width:1%;" . ((!empty($item['hex'])) ? 'background-color:#' . $item['hex'] . ";'" : "'") . "> </td>\n";
|
|
print "<td style='$this_row_style'>" . $item['hex'] . "</td>\n";
|
|
|
|
/* column 'Color Template' */
|
|
print '<td>';
|
|
if (!empty($item['hex'])) {
|
|
print "<select id='agg_color_" . $item['id'] ."' name='agg_color_" . $item['id'] ."'>";
|
|
print "<option value='0' selected>None</option>\n";
|
|
html_create_list($color_templates, "name", "color_template_id", ($is_edit && isset($current_vals[$item['id']]['color_template']) ? $current_vals[$item['id']]['color_template']:''));
|
|
print "</select>\n";
|
|
}
|
|
print '</td>';
|
|
|
|
/* column "Skip" */
|
|
if (!$force_skip) {
|
|
print "<td style='width:1%;text-align:center;'>";
|
|
print "<input class='checkbox' id='agg_skip_" . $item['id'] . "' type='checkbox' name='agg_skip_" . $item['id'] . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "' " . ($is_edit && (!isset($current_vals[$item['id']]['item_total']) || (isset($current_vals[$item['id']]['item_skip']) && $current_vals[$item['id']]['item_skip'] == 'on')) ? 'checked':'') . '>';
|
|
print '</td>';
|
|
|
|
/* column 'Total' */
|
|
print "<td style='width:1%;text-align:center;'>";
|
|
print "<input class='checkbox' id='agg_total_" . ($item['id']) . "' type='checkbox' name='agg_total_" . ($item['id']) . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "' " . ($is_edit && isset($current_vals[$item['id']]['item_total']) && $current_vals[$item['id']]['item_total'] == 'on' ? 'checked':'') . '>';
|
|
print '</td>';
|
|
} else {
|
|
print "<td style='width:1%;text-align:center;'><input class='checkbox' id='dummy_" . $item['id'] . "' disabled='disabled' type='checkbox' name='dummy_" . $item['id'] . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "' " . ($is_edit ? 'checked':'') . '></td>';
|
|
print "<td style='width:1%;text-align:center;'><input class='checkbox' id='dummy1_" . $item['id'] . "' disabled='disabled' type='checkbox' name='dummy1_" . $item['id'] . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "'>";
|
|
print "<input style='display:none;' class='checkbox' id='agg_skip_" . $item['id'] . "' type='checkbox' name='agg_skip_" . $item['id'] . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "' " . ($is_edit ? 'checked':'') . '>';
|
|
print "<input style='display:none;' class='checkbox' id='agg_total_" . ($item['id']) . "' type='checkbox' name='agg_total_" . ($item['id']) . "' title='" . htmlspecialchars($item['text_format'], ENT_QUOTES) . "'></td>";
|
|
}
|
|
|
|
print '</tr>';
|
|
|
|
$i++;
|
|
}
|
|
} else {
|
|
print "<tr><td colspan='7'><em>" . __('No Items') . "</em></td></tr>";
|
|
}
|
|
|
|
html_end_box();
|
|
|
|
form_hidden_box('item_no', sizeof($item_list), sizeof($item_list));
|
|
}
|
|
|
|
|
|
/**
|
|
* draw graph configuration form so user can override some graph template parametes
|
|
*
|
|
* @param int $aggregate_template_id - aggregate graph template beeing edited
|
|
* @param int $graph_template_id - graph template this aggregate template is based on
|
|
*/
|
|
function draw_aggregate_template_graph_config($aggregate_template_id, $graph_template_id) {
|
|
global $struct_graph;
|
|
|
|
html_start_box(__('Graph Configuration'), '100%', true, '3', 'center', '');
|
|
|
|
$aggregate_templates_graph = db_fetch_row_prepared('SELECT *
|
|
FROM aggregate_graph_templates_graph
|
|
WHERE aggregate_template_id = ?',
|
|
array($aggregate_template_id));
|
|
|
|
$graph_templates_graph = db_fetch_row_prepared('SELECT *
|
|
FROM graph_templates_graph
|
|
WHERE graph_template_id = ?',
|
|
array($graph_template_id));
|
|
|
|
$form_array = array();
|
|
|
|
foreach ($struct_graph as $field_name => $field_array) {
|
|
if ($field_name == 'title')
|
|
continue;
|
|
|
|
if ($field_array['method'] != 'spacer') {
|
|
$form_array += array($field_name => $struct_graph[$field_name]);
|
|
|
|
/* value from graph template or aggregate graph template
|
|
(based on value of t_$field_name of aggregate_template_graph) */
|
|
if (sizeof($aggregate_templates_graph) && $aggregate_templates_graph['t_'.$field_name] == 'on') {
|
|
$value = $aggregate_templates_graph[$field_name];
|
|
} else {
|
|
$value = $graph_templates_graph[$field_name];
|
|
}
|
|
|
|
$form_array[$field_name]['value'] = $value;
|
|
$form_array[$field_name]['sub_checkbox'] = array(
|
|
'name' => 't_' . $field_name,
|
|
'friendly_name' => __('Override this Value'). '<br>',
|
|
'value' => (sizeof($aggregate_templates_graph) ? $aggregate_templates_graph{'t_' . $field_name} : ''),
|
|
'on_change' => 'toggleFieldEnabled(this);'
|
|
);
|
|
} else {
|
|
$form_array += array($field_name => $struct_graph[$field_name]);
|
|
}
|
|
}
|
|
|
|
draw_edit_form(
|
|
array(
|
|
'config' => array('no_form_tag' => true),
|
|
'fields' => $form_array
|
|
)
|
|
);
|
|
|
|
html_end_box(false, true);
|
|
|
|
/* some javascript do dinamically disable non-overriden fields */
|
|
?>
|
|
<script type='text/javascript'>
|
|
|
|
$(function() {
|
|
setFieldsDisabled();
|
|
});
|
|
|
|
// disable all items with sub-checkboxes except
|
|
// where sub-checkbox checked
|
|
function setFieldsDisabled() {
|
|
$('tr[id*="row_"]').each(function() {
|
|
fieldName = this.id.substr(4);
|
|
cbName = 't_'+fieldName;
|
|
if ($('#'+cbName).size() > 0) {
|
|
$('#'+fieldName).prop('disabled', !$('#'+cbName).is(':checked'));
|
|
}
|
|
});
|
|
}
|
|
|
|
// enable or disable form field based on state of corresponding checkbox
|
|
function toggleFieldEnabled(cb) {
|
|
prefix = 't_';
|
|
if (cb.name.substr(0,prefix.length) == prefix) {
|
|
fieldName = cb.name.substr(prefix.length);
|
|
$('#'+fieldName).prop('disabled', !cb.checked);
|
|
}
|
|
}
|
|
|
|
</script>
|
|
<?php
|
|
}
|
|
|