web: initial checkin
|
@ -0,0 +1,11 @@
|
|||
// $Id$
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
1. install this module in your contributed modules directory
|
||||
2. add a symlink in the module's root dir to the rrdtool executable
|
||||
e.g. ln -s /usr/bin/rrdtool rrdtool
|
||||
3. add following directory structure in this module's root dir
|
||||
mkdir -p data/base data/night graphs/hour graphs/day graphs/week graphs/month graphs/year graphs/night
|
||||
|
||||
enjoy!
|
|
@ -0,0 +1,8 @@
|
|||
; $Id$
|
||||
name = Logger
|
||||
description = Logs metering values reported through XML-RPC in an RRD database and renders them in different charts.
|
||||
package = Metering
|
||||
core = 6.x
|
||||
version = 6.x-0.2
|
||||
dependencies[] = autotimezone
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
<?php
|
||||
// Copyright (c) 2009 jokamajo.org
|
||||
// $Id$
|
||||
|
||||
function logger_schema() {
|
||||
$schema['logger_devices'] = array(
|
||||
'description' => t("Contains the Fluksometer device ID's."),
|
||||
'fields' => array(
|
||||
'device' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '32',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'sha' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '32',
|
||||
'not null' => FALSE,
|
||||
),
|
||||
'created' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'access' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'version' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'upgrade' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'resets' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'uptime' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'memtotal' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'memfree' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'memcached' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'membuffers' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
),
|
||||
'uart_oe' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'size' => 'small',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '5',
|
||||
)
|
||||
),
|
||||
'primary key' => array('device'),
|
||||
);
|
||||
|
||||
$schema['logger_meters'] = array(
|
||||
'description' => t("Contains the Fluksometer meter ID's."),
|
||||
'fields' => array(
|
||||
'meter' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '32',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'uid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'device' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '32',
|
||||
'not null' => TRUE,
|
||||
'default' => '0',
|
||||
),
|
||||
'created' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'access' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'night' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'type' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '16',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'function' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '16',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'value' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'factor' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 1,
|
||||
'disp-width' => '10',
|
||||
),
|
||||
'unit' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => '16',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('meter'),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
function logger_install() {
|
||||
drupal_install_schema('logger');
|
||||
drupal_set_message(t('Created logger module tables {logger_devices} and {logger_meters}.'));
|
||||
}
|
||||
|
||||
function logger_uninstall() {
|
||||
drupal_uninstall_schema('logger');
|
||||
drupal_set_message(t('Deleted logger module tables {logger_devices} and {logger_meters}.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* R5.x update
|
||||
*/
|
||||
function logger_update_1() {
|
||||
$items = array();
|
||||
switch ($GLOBALS['db_type']) {
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
$items[] = update_sql("ALTER TABLE {logger_meters} ADD COLUMN night int unsigned NOT NULL default '0' AFTER access");
|
||||
break;
|
||||
case 'pgsql':
|
||||
break;
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* update to run with logger module's 6.x code
|
||||
*/
|
||||
function logger_update_6000() {
|
||||
$items = array();
|
||||
switch ($GLOBALS['db_type']) {
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN sha varchar(32) AFTER uid");
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN memtotal smallint unsigned NOT NULL default '0'");
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN memfree smallint unsigned NOT NULL default '0'");
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN memcached smallint unsigned NOT NULL default '0'");
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN membuffers smallint unsigned NOT NULL default '0'");
|
||||
$items[] = update_sql("ALTER TABLE {logger_devices} ADD COLUMN uart_oe smallint unsigned NOT NULL default '0'");
|
||||
break;
|
||||
case 'pgsql':
|
||||
break;
|
||||
}
|
||||
return $items;
|
||||
}
|
|
@ -0,0 +1,448 @@
|
|||
<?php
|
||||
|
||||
//
|
||||
// logger.module : support module for charting data stored in RRD's
|
||||
// Copyright (c) 2008-2009 jokamajo.org
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Logs metering values reported through XML-RPC in the Drupal & RRD database and displays them in different charts
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
define('RED', 'F1572F');
|
||||
define('BLUE', '44C3D3');
|
||||
define('GREEN', '7AAB5A');
|
||||
define('ORANGE', 'F37E2B');
|
||||
define('YELLOW', 'FBEB0D');
|
||||
define('PURPLE', 'A052A0');
|
||||
|
||||
/**
|
||||
* Implementation of hook_perm().
|
||||
*/
|
||||
function logger_perm() {
|
||||
return array('logger');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_menu() for logger
|
||||
* Don't forget to create a primary menu item in the Drupal administration section with the title 'ecology' linking to the '/logger' path
|
||||
*/
|
||||
function logger_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['admin/settings/logger'] = array(
|
||||
'title' => 'Logger settings',
|
||||
'description' => 'Configure settings for logging metering values.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('_logger_admin_settings'),
|
||||
'access arguments' => array('administer site configuration'),
|
||||
);
|
||||
$items['logger'] = array(
|
||||
'title' => 'your dashboard', // isn't printed as title on the page, therefore resort to drupal_set_title (t('your ecological dashboard')) in ecology_dashboard;
|
||||
'description' => 'Configure settings for logging metering values.',
|
||||
'page callback' => '_logger_dashboard', //takes the callback from the MENU_DEFAULT_LOCAL_TASK -> lightest level-two menu
|
||||
'page arguments' => array('electricity', 'main', 'hour'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['logger/add'] = array(
|
||||
'title' => 'add this user to the chart',
|
||||
'page callback' => '_logger_add',
|
||||
'access arguments' => array('logger'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['logger/remove'] = array(
|
||||
'title' => 'remove this user from the chart',
|
||||
'page callback' => '_logger_remove',
|
||||
'access arguments' => array('logger'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['logger/unit'] = array(
|
||||
'title' => 'change the unit',
|
||||
'page callback' => '_logger_unit',
|
||||
'access arguments' => array('logger'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['logger/electricity'] = array(
|
||||
'title' => 'electricity',
|
||||
// 'page callback' => '_logger_dashboard',
|
||||
// 'page arguments' => array('electricity', 'main', 'hour'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
);
|
||||
|
||||
/**
|
||||
$items['logger/water'] = array(
|
||||
'title' => 'water',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('water', 'main', 'hour'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
$items['logger/gas'] = array(
|
||||
'title' => 'gas',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('gas', 'main', 'hour'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
**/
|
||||
|
||||
$items['logger/electricity/hour'] = array(
|
||||
'title' => 'hour',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('electricity', 'main', 'hour'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 0,
|
||||
);
|
||||
$items['logger/electricity/day'] = array(
|
||||
'title' => 'day',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('electricity', 'main', 'day'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 1,
|
||||
);
|
||||
$items['logger/electricity/month'] = array(
|
||||
'title' => 'month',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('electricity', 'main', 'month'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 2,
|
||||
);
|
||||
$items['logger/electricity/year'] = array(
|
||||
'title' => 'year',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('electricity', 'main', 'year'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 3,
|
||||
);
|
||||
$items['logger/electricity/night'] = array(
|
||||
'title' => 'night',
|
||||
'page callback' => '_logger_dashboard',
|
||||
'page arguments' => array('electricity', 'main', 'night'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 4,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions registered in the logger_menu section
|
||||
*/
|
||||
function _logger_dashboard($type, $function, $interval) {
|
||||
watchdog('dashboard', 'arguments: %type, %function, %interval', array('%type' => $type, '%function' => $function, '%interval' => $interval), WATCHDOG_DEBUG);
|
||||
|
||||
if (user_access('logger')) {
|
||||
drupal_set_title(t('your dashboard'));
|
||||
global $user;
|
||||
}
|
||||
else { //show users who don't have 'logger' permissions icrarus'es chart
|
||||
drupal_set_title(t("a Fluksonian's dashboard"));
|
||||
$user = new stdClass();
|
||||
$user->uid = 1;
|
||||
$user->name = 'icarus75';
|
||||
$user->timezone = '3600';
|
||||
}
|
||||
|
||||
$root_path = drupal_get_path('module', 'logger');
|
||||
$graph_path = $root_path .'/graphs/'. $interval .'/';
|
||||
$pngid = md5(uniqid()); //generate random numbers for the png chart so that the browser doesn't use the cached one, use cron to clean up the dir hourly
|
||||
switch ($interval) {
|
||||
case 'hour':
|
||||
$data_path = $root_path .'/data/base/';
|
||||
$start = 'end-1h';
|
||||
break;
|
||||
case 'day':
|
||||
$data_path = $root_path .'/data/base/';
|
||||
$start = 'end-1d';
|
||||
break;
|
||||
case 'month':
|
||||
$data_path = $root_path .'/data/base/';
|
||||
$start = 'end-60d';
|
||||
break;
|
||||
case 'year':
|
||||
$data_path = $root_path .'/data/base/';
|
||||
$start = 'end-1y';
|
||||
break;
|
||||
case 'night':
|
||||
$data_path = $root_path .'/data/night/';
|
||||
$start = 'end-60d';
|
||||
break;
|
||||
}
|
||||
|
||||
$meter = db_fetch_object(db_query("SELECT meter, unit FROM {logger_meters} WHERE uid = %d AND type = '%s' AND function = '%s'", $user->uid, $type, $function));
|
||||
switch ($type) {
|
||||
case 'electricity':
|
||||
switch ($meter->unit) {
|
||||
case 'watt':
|
||||
$meter->factor = 3600; // 1Wh/s = 3600 W
|
||||
break;
|
||||
case 'kwh':
|
||||
$meter->unit = 'kWh/year';
|
||||
$meter->factor = 31536;
|
||||
break;
|
||||
case 'eur':
|
||||
$meter->unit = 'euro/year';
|
||||
$meter->factor = 5361.12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$color = array(RED, BLUE, GREEN, YELLOW, PURPLE);
|
||||
$string->def = ' DEF:data0='. $data_path . $meter->meter .'.rrd:meter:AVERAGE CDEF:meter0=data0,'. $meter->factor .',* VDEF:min0=meter0,MINIMUM VDEF:max0=meter0,MAXIMUM VDEF:avg0=meter0,AVERAGE VDEF:last0=meter0,LAST';
|
||||
$string->line = ' COMMENT:"\s" LINE1:meter0#'. $color[0] .':'.'"'. substr($user->name.' ', 0, 15) .'"'.' GPRINT:min0:"min\:%5.0lf" GPRINT:max0:"\tmax\:%5.0lf" GPRINT:avg0:"\tavg\:%5.0lf" GPRINT:last0:"\tlast\:%5.0lf\l"';
|
||||
|
||||
if (user_access('logger') || user_access('staff')) { //allow Veerle to watch the graphs
|
||||
$result = db_query("SELECT u.name, lm.meter FROM (({users} u INNER JOIN {user_relationships} ur ON u.uid = ur.requestee_id) INNER JOIN {user_relationship_types} urt ON ur.rtid = urt.rtid) INNER JOIN {logger_meters} lm ON u.uid = lm.uid WHERE ur.requester_id = %d AND urt.name = '%s' AND type = '%s' AND function = '%s' ORDER BY ur.rid", $user->uid, 'subscription', $type, $function);
|
||||
$i = 0;
|
||||
while ($subscription = db_fetch_object($result)) {
|
||||
$i += 1;
|
||||
// print_r($subscription);
|
||||
$string->def .= ' DEF:data'. $i .'='. $data_path . $subscription->meter .'.rrd:meter:AVERAGE CDEF:meter'. $i .'=data'. $i .','. $meter->factor .',* VDEF:min'. $i .'=meter'. $i .',MINIMUM VDEF:max'. $i .'=meter'. $i .',MAXIMUM VDEF:avg'. $i .'=meter'. $i .',AVERAGE VDEF:last'. $i .'=meter'. $i .',LAST';
|
||||
$string->line .= ' LINE1:meter'. $i .'#'. $color[$i] .':'.'"'. substr($subscription->name.' ', 0, 15) .'"'.' GPRINT:min'. $i .':"min\:%5.0lf" GPRINT:max'. $i .':"\tmax\:%5.0lf" GPRINT:avg'. $i .':"\tavg\:%5.0lf" GPRINT:last'. $i .':"\tlast\:%5.0lf\l"';
|
||||
}
|
||||
}
|
||||
|
||||
//construct the TZ=GMT-02:00 format from the $user->timezone object updated by the autotimezone module
|
||||
if ($user->timezone >= 0)
|
||||
$TZ = 'TZ="GMT-';
|
||||
else
|
||||
$TZ = 'TZ="GMT+';
|
||||
$TZ .= gmdate('h:i', abs($user->timezone)) .'" ';
|
||||
//insert the TZ prior to launching rrdtool to obtain a proper time conversion
|
||||
$command = $TZ . $root_path .'/rrdtool graph '. $graph_path . $pngid .'.png -s '. $start .' --vertical-label '. $meter->unit .' --lower-limit 0 -w 500 -h 350 -E -X 0 --font LEGEND:8:';
|
||||
$command .= $string->def;
|
||||
$command .= $string->line;
|
||||
exec($command, $output, $return_var);
|
||||
watchdog('dashboard', 'arguments: %command ++ %output ++ %return_var', array('%command' => $command, '%output' => serialize($output), '%return_var' => $return_var), WATCHDOG_DEBUG);
|
||||
return theme('chart', $graph_path . $pngid .'.png');
|
||||
}
|
||||
|
||||
function _logger_add($uid) {
|
||||
// TODO : include security checks
|
||||
global $user;
|
||||
$rtid = db_result(db_query("SELECT rtid FROM {user_relationship_types} where name = '%s'", 'subscription'));
|
||||
user_relationships_request_relationship($user->uid, $uid, $rtid, TRUE);
|
||||
$destination = drupal_get_destination();
|
||||
drupal_goto($destination);
|
||||
}
|
||||
|
||||
function _logger_remove($rid) {
|
||||
// TODO : include security checks
|
||||
db_query("DELETE FROM {user_relationships} WHERE rid = %d", $rid);
|
||||
$destination = drupal_get_destination();
|
||||
drupal_goto($destination);
|
||||
}
|
||||
|
||||
function _logger_unit($unit) {
|
||||
// TODO : include security checks
|
||||
global $user;
|
||||
// hardcoded type and function
|
||||
db_query("UPDATE {logger_meters} SET unit = '%s' WHERE uid = %d AND type = '%s' AND function = '%s'", $unit, $user->uid, 'electricity', 'main');
|
||||
$destination = drupal_get_destination();
|
||||
drupal_goto($destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_theme() for logger
|
||||
*/
|
||||
function logger_theme() {
|
||||
return array(
|
||||
'chart' => array(
|
||||
'arguments' => array('chart' => NULL),
|
||||
),
|
||||
'logger_item_list' => array(
|
||||
'arguments' => array('items' => NULL, 'title' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Theming the chart
|
||||
*/
|
||||
function theme_chart($chart) {
|
||||
$output .= '<p id="chart"><img src="'. base_path() . $chart .'" alt="Flukso"/></p><!-- end chart-->';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_block() for logger
|
||||
* Adds two blocks to the logger pages for (de-)selecting users and
|
||||
* another one for selecting the desired unit
|
||||
*/
|
||||
function logger_block($op = 'list', $delta = 0, $edit = array()) {
|
||||
global $user;
|
||||
|
||||
switch ($op) {
|
||||
case 'list':
|
||||
$blocks['subscriptions']['info'] = t('Subscriptions');
|
||||
$blocks['subscriptions']['status'] = TRUE;
|
||||
$blocks['subscriptions']['region'] = 'right';
|
||||
$blocks['subscriptions']['weight'] = 0;
|
||||
$blocks['subscriptions']['pages'] = 'logger<br />logger/*';
|
||||
|
||||
$blocks['fluksonians']['info'] = t('Fluksonians');
|
||||
$blocks['fluksonians']['status'] = TRUE;
|
||||
$blocks['fluksonians']['region'] = 'right';
|
||||
$blocks['fluksonians']['weight'] = 1;
|
||||
$blocks['fluksonians']['pages'] = 'logger<br />logger/*';
|
||||
|
||||
$blocks['unit']['info'] = t('Unit');
|
||||
$blocks['unit']['status'] = TRUE;
|
||||
$blocks['unit']['region'] = 'right';
|
||||
$blocks['unit']['weight'] = 2;
|
||||
$blocks['unit']['pages'] = 'logger<br />logger/*';
|
||||
|
||||
$blocks['publish']['info'] = t('Publish');
|
||||
$blocks['publish']['status'] = TRUE;
|
||||
$blocks['publish']['region'] = 'content';
|
||||
$blocks['publish']['weight'] = 3;
|
||||
$blocks['publish']['pages'] = 'logger<br />logger/*';
|
||||
|
||||
return $blocks;
|
||||
|
||||
case 'view':
|
||||
//pass along our current destination in the query string so that logger_add and logger_remove can return after processing their task
|
||||
$destination = drupal_get_destination();
|
||||
|
||||
if ($delta == 'subscriptions' && user_access('logger')) {
|
||||
$result = db_query("SELECT u.uid, u.name, ur.rid FROM ({users} u INNER JOIN {user_relationships} ur ON u.uid = ur.requestee_id) INNER JOIN {user_relationship_types} urt ON ur.rtid = urt.rtid WHERE ur.requester_id = %d AND urt.name = '%s' ORDER BY ur.rid", $user->uid, 'subscription');
|
||||
$items = array();
|
||||
while ($subscription = db_fetch_object($result)) {
|
||||
$items[] = l('[x]', 'logger/remove/'. $subscription->rid, array('attributes' => array('title' => "unsubscribe from ". $subscription->name ."'s stream"), 'query' => $destination)) .' '. l($subscription->name, 'user/'. $subscription->uid, array());
|
||||
}
|
||||
$block['subject'] = t('Subscriptions');
|
||||
$block['content'] = theme('logger_item_list', $items);
|
||||
}
|
||||
|
||||
elseif ($delta == 'fluksonians' && user_access('logger')) {
|
||||
// list all users having the fluksionian role for now
|
||||
// to be replaced by a real buddylist later on
|
||||
$result = db_query("SELECT u.uid, u.name FROM ({users} u INNER JOIN {users_roles} ur ON u.uid = ur.uid) INNER JOIN {role} r ON ur.rid = r.rid WHERE r.name = '%s' AND NOT u.uid = %d ORDER BY u.name", 'fluksonian', $user->uid);
|
||||
$items = array();
|
||||
while ($fluksonian = db_fetch_object($result)) {
|
||||
$items[] = l('[+]', 'logger/add/'. $fluksonian->uid, array('attributes' => array('title' => "subscribe to ". $fluksonian->name ."'s stream"), 'query' => $destination)) .' '. l($fluksonian->name, 'user/'. $fluksonian->uid, array());
|
||||
}
|
||||
$block['subject'] = t('Fluksonians');
|
||||
$block['content'] = theme('logger_item_list', $items);
|
||||
}
|
||||
|
||||
elseif ($delta == 'unit' && user_access('logger')) {
|
||||
//hardcoded the type and function parameters for now
|
||||
$unit = db_result(db_query("SELECT unit FROM {logger_meters} WHERE uid = %d AND type = '%s' AND function = '%s'", $user->uid, 'electricity', 'main'));
|
||||
$items = array();
|
||||
switch ($unit) {
|
||||
case 'watt':
|
||||
$items[] = 'watt';
|
||||
$items[] = l('kWh/year', 'logger/unit/kwh', array('attributes' => array('title' => "switch to kWh/year"), 'query' => $destination));
|
||||
$items[] = l('euro/year', 'logger/unit/eur', array('attributes' => array('title' => "switch to euro/year"), 'query' => $destination));
|
||||
break;
|
||||
case 'kwh':
|
||||
$items[] = l('watt', 'logger/unit/watt', array('attributes' => array('title' => "switch to watt"), 'query' => $destination));
|
||||
$items[] = 'kWh/year';
|
||||
$items[] = l('euro/year', 'logger/unit/eur', array('attributes' => array('title' => "switch to euro/year"), 'query' => $destination));
|
||||
break;
|
||||
case 'eur':
|
||||
$items[] = l('watt', 'logger/unit/watt', array('attributes' => array('title' => "switch to watt"), 'query' => $destination));
|
||||
$items[] = l('kWh/year', 'logger/unit/kwh', array('attributes' => array('title' => "switch to kWh/year"), 'query' => $destination));
|
||||
$items[] = 'euro/year';
|
||||
break;
|
||||
}
|
||||
$block['subject'] = t('Unit');
|
||||
$block['content'] = theme('logger_item_list', $items);
|
||||
}
|
||||
|
||||
elseif ($delta == 'publish' && user_access('logger')) {
|
||||
// $block['subject'] = t('Publish');
|
||||
$block['content'] = drupal_get_form('_logger_publish_form');
|
||||
}
|
||||
|
||||
return $block;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementing a simple non-bulleted list for the logger_block
|
||||
*/
|
||||
function theme_logger_item_list($items, $title = NULL) {
|
||||
$output = '';
|
||||
foreach ($items as $item) {
|
||||
$output .= $item .'<br />';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the publish block form.
|
||||
*/
|
||||
function _logger_publish_form() {
|
||||
$form['publish'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Publish'),
|
||||
'#description' => t('Publish the chart.'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE
|
||||
);
|
||||
$form['publish']['title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Title'),
|
||||
'#description' => t('Please enter the title of your post.')
|
||||
);
|
||||
$form['publish']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Publish')
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process publish form submissions.
|
||||
*/
|
||||
function _logger_publish_form_submit($form, &$form_state) {
|
||||
$form_state['redirect'] = 'node/add'; //placeholder; check whether we can automatically fill in the new content type
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the administration settings form for the logger module
|
||||
*/
|
||||
function _logger_admin_settings() {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_cron().
|
||||
* Cron will call this hook periodically [e.g. 1 hour interval] to perform housekeeping on the png's.
|
||||
*/
|
||||
function logger_cron() {
|
||||
exec('rm sites/all/modules/custom/logger/graphs/hour/*');
|
||||
exec('rm sites/all/modules/custom/logger/graphs/day/*');
|
||||
exec('rm sites/all/modules/custom/logger/graphs/month/*');
|
||||
exec('rm sites/all/modules/custom/logger/graphs/year/*');
|
||||
exec('rm sites/all/modules/custom/logger/graphs/night/*');
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
Index: .htaccess
|
||||
===================================================================
|
||||
RCS file: /cvs/drupal/drupal/.htaccess,v
|
||||
retrieving revision 1.90.2.3
|
||||
diff -u -p -r1.90.2.3 .htaccess
|
||||
--- .htaccess 10 Dec 2008 20:04:08 -0000 1.90.2.3
|
||||
+++ .htaccess 3 Aug 2009 22:38:00 -0000
|
||||
@@ -100,10 +100,13 @@ DirectoryIndex index.php
|
||||
# uncomment the following line:
|
||||
# RewriteBase /
|
||||
|
||||
+ RewriteRule ^xmlrpc/([0-9]+)/?$ xmlrpc.php?version=$1 [L]
|
||||
+
|
||||
# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_URI} !=/favicon.ico
|
||||
+ RewriteCond %{REQUEST_URI} !=/xmlrpc(.*)
|
||||
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
|
||||
</IfModule>
|
||||
|
||||
Index: xmlrpc.php
|
||||
===================================================================
|
||||
RCS file: /cvs/drupal/drupal/xmlrpc.php,v
|
||||
retrieving revision 1.15
|
||||
diff -u -p -r1.15 xmlrpc.php
|
||||
--- xmlrpc.php 10 Dec 2005 19:26:47 -0000 1.15
|
||||
+++ xmlrpc.php 3 Aug 2009 22:38:00 -0000
|
||||
@@ -6,9 +6,77 @@
|
||||
* PHP page for handling incoming XML-RPC requests from clients.
|
||||
*/
|
||||
|
||||
+// define xmlrpc method location
|
||||
+define('XMLRPC_PATH', 'sites/all/modules');
|
||||
+define('XMLRPC_MODULE', 'logger');
|
||||
+define('XMLRPC_FILE', 'xmlrpc');
|
||||
+
|
||||
+// defined xmlrpc endpoints
|
||||
+$xmlrpc_versions = array('', 1);
|
||||
+
|
||||
+// any common.inc or other core functions that xmlrpc processing relies upon
|
||||
+function t($string, $args = array(), $langcode = NULL) {
|
||||
+ if (empty($args)) {
|
||||
+ return $string;
|
||||
+ }
|
||||
+ else {
|
||||
+ // Transform arguments before inserting them.
|
||||
+ foreach ($args as $key => $value) {
|
||||
+ switch ($key[0]) {
|
||||
+ case '@':
|
||||
+ case '%':
|
||||
+ default:
|
||||
+ // Escaped only.
|
||||
+ $args[$key] = check_plain($value);
|
||||
+ break;
|
||||
+
|
||||
+ case '!':
|
||||
+ // Pass-through.
|
||||
+ }
|
||||
+ }
|
||||
+ return strtr($string, $args);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+function watchdog_xmlrpc($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
|
||||
+ global $base_root;
|
||||
+
|
||||
+ $current_db = db_set_active();
|
||||
+
|
||||
+ db_query("INSERT INTO {watchdog}
|
||||
+ (type, message, variables, severity, link, location, referer, hostname, timestamp)
|
||||
+ VALUES
|
||||
+ ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', %d)",
|
||||
+ $type,
|
||||
+ $message,
|
||||
+ serialize($variables),
|
||||
+ $severity,
|
||||
+ $link,
|
||||
+ $base_root . request_uri(),
|
||||
+ referer_uri(),
|
||||
+ ip_address(),
|
||||
+ time());
|
||||
+
|
||||
+ if ($current_db) {
|
||||
+ db_set_active($current_db);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
include_once './includes/bootstrap.inc';
|
||||
-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
||||
+drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
|
||||
include_once './includes/xmlrpc.inc';
|
||||
include_once './includes/xmlrpcs.inc';
|
||||
|
||||
-xmlrpc_server(module_invoke_all('xmlrpc'));
|
||||
+if (in_array($_REQUEST['version'], $xmlrpc_versions)) {
|
||||
+ require_once XMLRPC_PATH . '/' . XMLRPC_MODULE . '/' . XMLRPC_FILE . $_REQUEST['version'] . '.inc';
|
||||
+
|
||||
+ //debugging watchdog_xmlrpc('xmlrpc', 'xmlrpc api called with version %version', array('%version' => $_REQUEST['version']), WATCHDOG_DEBUG);
|
||||
+
|
||||
+ $function = XMLRPC_MODULE . '_xmlrpc';
|
||||
+ $callbacks = $function();
|
||||
+ xmlrpc_server($callbacks);
|
||||
+}
|
||||
+else {
|
||||
+ xmlrpc_server_error(-32601, t('Server error. Requested method version (@version) not specified.', array("@version" => $_REQUEST['version'])));
|
||||
+}
|
||||
Index: includes/menu.inc
|
||||
===================================================================
|
||||
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
|
||||
retrieving revision 1.255.2.31
|
||||
diff -u -p -r1.255.2.31 menu.inc
|
||||
--- includes/menu.inc 27 Apr 2009 12:50:13 -0000 1.255.2.31
|
||||
+++ includes/menu.inc 3 Aug 2009 22:38:02 -0000
|
||||
@@ -1422,8 +1422,8 @@ function menu_local_tasks($level = 0, $r
|
||||
return $root_path;
|
||||
}
|
||||
else {
|
||||
- // We do not display single tabs.
|
||||
- return (isset($tabs[$level]) && $tabs[$level]['count'] > 1) ? $tabs[$level]['output'] : '';
|
||||
+ // We do not display single tabs: BVDM yes we do for flukso!
|
||||
+ return (isset($tabs[$level])) ? $tabs[$level]['output'] : '';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
? menu.allow.display.of.single.tabs.patch
|
||||
Index: menu.inc
|
||||
===================================================================
|
||||
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
|
||||
retrieving revision 1.255.2.31
|
||||
diff -u -p -r1.255.2.31 menu.inc
|
||||
--- menu.inc 27 Apr 2009 12:50:13 -0000 1.255.2.31
|
||||
+++ menu.inc 3 Aug 2009 20:19:06 -0000
|
||||
@@ -1422,8 +1422,8 @@ function menu_local_tasks($level = 0, $r
|
||||
return $root_path;
|
||||
}
|
||||
else {
|
||||
- // We do not display single tabs.
|
||||
- return (isset($tabs[$level]) && $tabs[$level]['count'] > 1) ? $tabs[$level]['output'] : '';
|
||||
+ // We do not display single tabs: BVDM yes we do for flukso!
|
||||
+ return (isset($tabs[$level])) ? $tabs[$level]['output'] : '';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
//
|
||||
// xmlrpc.inc : data and management plane xmlrpc methods for logging metering data
|
||||
// aplha version API
|
||||
//
|
||||
// Copyright (c) 2008-2009 jokamajo.org
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* Implementation of hook_xmlrpc().
|
||||
* Mapping external XML-RPC methods to callback functions.
|
||||
* API versioning; logger.flukso.net/xmlrpc.php maps to xmlrpc.inc
|
||||
*/
|
||||
function logger_xmlrpc() {
|
||||
return array(
|
||||
array(
|
||||
'logger.heartbeat', // External method name.
|
||||
'_logger_heartbeat', // Drupal callback function to run.
|
||||
array('int', 'string', 'int', 'int', 'int'), // Return value's type, then any parameter types (upgrade, device, version, resets, uptime)
|
||||
'Send a heartbeat to the logger.' // Description.
|
||||
),
|
||||
array(
|
||||
'logger.measurementAdd', // External method name.
|
||||
'_logger_measurement_add', // Drupal callback function to run.
|
||||
array('string', 'array'), // Return value's type, then any parameter types (return, measurements)
|
||||
'Submit measurements to the logger.' // Description.
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions registered in the logger_xmlrpc section
|
||||
*/
|
||||
function _logger_heartbeat($device, $version, $resets, $uptime) {
|
||||
$dev = db_fetch_object(db_query("SELECT upgrade, resets FROM {logger_devices} WHERE device = '%s'", $device));
|
||||
$dev->resets += $resets;
|
||||
db_query("UPDATE {logger_devices} SET access = %d, version = %d, upgrade = %d, resets = %d, uptime = %d WHERE device = '%s'", time(), $version, 0, $dev->resets, $uptime, $device);
|
||||
return $dev->upgrade;
|
||||
}
|
||||
|
||||
function _logger_measurement_add($logs) {
|
||||
$info = 'added 5min interval measurements to the log';
|
||||
$path = new stdClass();
|
||||
$path->root = XMLRPC_PATH . '/' . XMLRPC_MODULE; // need to hardcode drupal_get_path('module', 'logger');
|
||||
$path->base = $path->root .'/data/base/';
|
||||
$path->night = $path->root .'/data/night/';
|
||||
foreach ($logs as $meter => $measurements) {
|
||||
//load the normalisation factor, relative to 1pulse = 1Wh
|
||||
$meterdata = db_fetch_object(db_query("SELECT night, factor FROM {logger_meters} WHERE meter = '%s'", $meter));
|
||||
$command = $path->root .'/rrdtool update '. $path->base . $meter .'.rrd ';
|
||||
ksort($measurements); // sort the key-value pairs in the associative array by key, i.e. the timestamp
|
||||
foreach ($measurements as $timestamp => $value) {
|
||||
if (is_numeric($timestamp) and is_numeric($value)) {
|
||||
$command .= $timestamp .':'. $value*$meterdata->factor .' ';
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'corrupted input data for %meter : %timestamp : %value', array('%meter' => $meter, '%timestamp' => $timestamp, '%value' => $value), WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
system($command, $return);
|
||||
if ($return == 0) {
|
||||
// update the night rrd every day at 6AM UTC
|
||||
if (time() > $meterdata->night) {
|
||||
$timestamp = floor(time()/86400)*86400;
|
||||
$start = $timestamp + 3600;
|
||||
$end = $start + 10800; //3h time interval
|
||||
$command = $path->root ."/rrdtool fetch ". $path->base . $meter .".rrd AVERAGE -r 900 -s ". $start ." -e ". $end ." | tail -n 12 | awk -F': ' '{SUM += $2} END {print SUM/12}'";
|
||||
$night = (float)shell_exec($command); //test shell_exec iso system
|
||||
$command = $path->root .'/rrdtool update '. $path->night . $meter .'.rrd '. $timestamp .':'. $night;
|
||||
system($command, $return);
|
||||
if ($return == 0) {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'successful update for night rrd: %command', array('%command' => $command), WATCHDOG_NOTICE); //debugging
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'error updating night rrd: %command', array('%command' => $command), WATCHDOG_ERROR); //debugging
|
||||
}
|
||||
$meterdata->night = $timestamp + 104400; //add an offset of 29h, i.e. 5AM UTC next day
|
||||
}
|
||||
// {logger_meters} is updated with the true metervalue $value, NOT $value*$meterdata->factor since we're not normalising this entry!
|
||||
db_query("UPDATE {logger_meters} SET access = %d, night = %d, value = %d WHERE meter = '%s'", time(), $meterdata->night, $value, $meter);
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'shell command execution failed: %return %command', array('%command' => $command, '%return' => $return), WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
return $command; //using $command for testing purposes, replace by $info afterwards
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
//
|
||||
// xmlrpc1.inc : data and management plane xmlrpc methods for logging metering data
|
||||
// API version 1
|
||||
//
|
||||
// Copyright (c) 2008-2009 jokamajo.org
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* Implementation of hook_xmlrpc().
|
||||
* Mapping external XML-RPC methods to callback functions.
|
||||
* API versioning; logger.flukso.net/xmlrpc/1 maps to xmlrpc1.inc
|
||||
*/
|
||||
function logger_xmlrpc() {
|
||||
return array(
|
||||
array(
|
||||
'logger.auth', // External method name.
|
||||
'_logger_auth', // Drupal callback function to run + api version 1
|
||||
array('string', 'array'), // Return value's type, then any parameter types (accept, auth)
|
||||
'Authenticate a device' // Description.
|
||||
),
|
||||
array(
|
||||
'logger.heartbeat', // External method name.
|
||||
'_logger_heartbeat', // Drupal callback function to run + api version 1
|
||||
array('array', 'array', 'array'), // Return value's type, then any parameter types (return, auth, monitor)
|
||||
'Send a heartbeat to the logger.' // Description.
|
||||
),
|
||||
array(
|
||||
'logger.measurementAdd', // External method name.
|
||||
'_logger_measurement_add', // Drupal callback function to run + api version 1
|
||||
array('string', 'array', 'array'), // Return value's type, then any parameter types (action, auth, logs)
|
||||
'Submit measurements to the logger.' // Description.
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback functions registered in the logger_xmlrpc section
|
||||
*/
|
||||
function _logger_auth($auth) {
|
||||
if (_logger_authenticate_hmac_sha1($auth))
|
||||
return 'authenticated!';
|
||||
else
|
||||
return xmlrpc_error(-31000, t('Authentication failed.'));
|
||||
}
|
||||
|
||||
function _logger_heartbeat($auth, $monitor) {
|
||||
if (_logger_authenticate_hmac_sha1($auth, $monitor)) {
|
||||
$device = db_fetch_object(db_query("SELECT sha, upgrade, resets FROM {logger_devices} WHERE device = '%s'", $auth['device']));
|
||||
$device->resets += $monitor['reset'];
|
||||
db_query("UPDATE {logger_devices} SET access = %d, version = %d, upgrade = %d, resets = %d, uptime = %d, memtotal = %d, memfree = %d, memcached = %d, membuffers = %d, uart_oe = %d WHERE device = '%s'", time(), $monitor['version'], 0, $device->resets, $monitor['uptime'], $monitor['memtotal'], $monitor['memfree'], $monitor['memcached'], $monitor['membuffers'], $monitor['uart_oe'], $auth['device']);
|
||||
|
||||
$action['upgrade'] = (int)$device->upgrade;
|
||||
if ($action['upgrade']) {
|
||||
$action['timestamp'] = time();
|
||||
$action['signature'] = hash_hmac('sha1', $action['timestamp'] .':'. $action['upgrade'] .':'. $device->sha, $device->sha);
|
||||
}
|
||||
return $action;
|
||||
}
|
||||
else
|
||||
return xmlrpc_error(-31000, t('Authentication failed.'));
|
||||
}
|
||||
|
||||
function _logger_measurement_add($auth, $logs) {
|
||||
if (_logger_authenticate_hmac_sha1($auth, $logs)) {
|
||||
$info = 'added 5min interval measurements to the log';
|
||||
$path = new stdClass();
|
||||
$path->root = XMLRPC_PATH . '/' . XMLRPC_MODULE; // need to hardcode drupal_get_path('module', 'logger');
|
||||
$path->base = $path->root .'/data/base/';
|
||||
$path->night = $path->root .'/data/night/';
|
||||
foreach ($logs as $meter => $measurements) {
|
||||
//load the normalisation factor, relative to 1pulse = 1Wh
|
||||
$meterdata = db_fetch_object(db_query("SELECT device, night, factor FROM {logger_meters} WHERE meter = '%s'", $meter));
|
||||
if ($meterdata->device == $auth['device']) { // extra security check
|
||||
$command = $path->root .'/rrdtool update '. $path->base . $meter .'.rrd ';
|
||||
ksort($measurements); // sort the key-value pairs in the associative array by key, i.e. the timestamp
|
||||
foreach ($measurements as $timestamp => $value) {
|
||||
if (is_numeric($timestamp) and is_numeric($value)) {
|
||||
$command .= $timestamp .':'. $value*$meterdata->factor .' ';
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'corrupted input data for %meter : %timestamp : %value', array('%meter' => $meter, '%timestamp' => $timestamp, '%value' => $value),WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
system($command, $return);
|
||||
|
||||
if ($return == 0) {
|
||||
// update the night rrd every day at 6AM UTC
|
||||
if (time() > $meterdata->night) {
|
||||
$timestamp = floor(time()/86400)*86400;
|
||||
$start = $timestamp + 3600;
|
||||
$end = $start + 10800; //3h time interval
|
||||
$command = $path->root ."/rrdtool fetch ". $path->base . $meter .".rrd AVERAGE -r 900 -s ". $start ." -e ". $end ." | tail -n 12 | awk -F': ' '{SUM += $2} END {print SUM/12}'";
|
||||
$night = (float)shell_exec($command); //test shell_exec iso system
|
||||
$command = $path->root .'/rrdtool update '. $path->night . $meter .'.rrd '. $timestamp .':'. $night;
|
||||
system($command, $return);
|
||||
if ($return == 0) {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'successful update for night rrd: %command', array('%command' => $command), WATCHDOG_NOTICE); //debugging
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'error updating night rrd: %command', array('%command' => $command), WATCHDOG_ERROR); //debugging
|
||||
}
|
||||
$meterdata->night = $timestamp + 104400; //add an offset of 29h, i.e. 5AM UTC next day
|
||||
}
|
||||
// {logger_meters} is updated with the true metervalue $value, NOT $value*$meterdata->factor since we're not normalising this entry!
|
||||
db_query("UPDATE {logger_meters} SET access = %d, night = %d, value = %d WHERE meter = '%s'", time(), $meterdata->night, $value, $meter);
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.measurementAdd', 'shell command execution failed: %return %command', array('%command' => $command, '%return' => $return), WATCHDOG_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $command; //using $command for testing purposes, replace by $info afterwards
|
||||
}
|
||||
else
|
||||
return xmlrpc_error(-31000, t('Authentication failed.'));
|
||||
}
|
||||
|
||||
function _logger_authenticate_hmac_sha1($auth, $message) {
|
||||
$auth['key'] = db_result(db_query("SELECT sha FROM {logger_devices} WHERE device = '%s'", $auth['device']));
|
||||
if (hash_hmac('sha1', $auth['timestamp'] .':'. _logger_serialise($message) .':'. $auth['key'], $auth['key']) == $auth['signature'] && $auth['timestamp'] > time() - 300) {
|
||||
// debugging: watchdog_xmlrpc('logger.auth', 'HMAC-SHA1 authentication succeeded for device: %device', array('%device' => $auth['device']), WATCHDOG_NOTICE);
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
watchdog_xmlrpc('logger.auth', 'HMAC-SHA1 authentication failed for device: %device', array('%device' => $auth['device']), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
function _logger_serialise($data) {
|
||||
if (is_array($data)) {
|
||||
$sequence = '';
|
||||
foreach ($data as $key => $value) {
|
||||
$sequence .= (string)$key . _logger_serialise($value);
|
||||
}
|
||||
return $sequence;
|
||||
}
|
||||
else {
|
||||
return (string)$data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
|
||||
verbatim copies of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom to
|
||||
share and change it. By contrast, the GNU General Public License is
|
||||
intended to guarantee your freedom to share and change free software--to
|
||||
make sure the software is free for all its users. This General Public License
|
||||
applies to most of the Free Software Foundation's software and to any other
|
||||
program whose authors commit to using it. (Some other Free Software
|
||||
Foundation software is covered by the GNU Library General Public License
|
||||
instead.) You can apply it to your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not price. Our
|
||||
General Public Licenses are designed to make sure that you have the
|
||||
freedom to distribute copies of free software (and charge for this service if
|
||||
you wish), that you receive source code or can get it if you want it, that you
|
||||
can change the software or use pieces of it in new free programs; and that
|
||||
you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to
|
||||
deny you these rights or to ask you to surrender the rights. These restrictions
|
||||
translate to certain responsibilities for you if you distribute copies of the
|
||||
software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether gratis or for
|
||||
a fee, you must give the recipients all the rights that you have. You must make
|
||||
sure that they, too, receive or can get the source code. And you must show
|
||||
them these terms so they know their rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and (2)
|
||||
offer you this license which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain that
|
||||
everyone understands that there is no warranty for this free software. If the
|
||||
software is modified by someone else and passed on, we want its recipients
|
||||
to know that what they have is not the original, so that any problems
|
||||
introduced by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We
|
||||
wish to avoid the danger that redistributors of a free program will individually
|
||||
obtain patent licenses, in effect making the program proprietary. To prevent
|
||||
this, we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and modification
|
||||
follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
|
||||
MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains a notice
|
||||
placed by the copyright holder saying it may be distributed under the terms
|
||||
of this General Public License. The "Program", below, refers to any such
|
||||
program or work, and a "work based on the Program" means either the
|
||||
Program or any derivative work under copyright law: that is to say, a work
|
||||
containing the Program or a portion of it, either verbatim or with
|
||||
modifications and/or translated into another language. (Hereinafter, translation
|
||||
is included without limitation in the term "modification".) Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not covered
|
||||
by this License; they are outside its scope. The act of running the Program is
|
||||
not restricted, and the output from the Program is covered only if its contents
|
||||
constitute a work based on the Program (independent of having been made
|
||||
by running the Program). Whether that is true depends on what the Program
|
||||
does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's source
|
||||
code as you receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice and
|
||||
disclaimer of warranty; keep intact all the notices that refer to this License
|
||||
and to the absence of any warranty; and give any other recipients of the
|
||||
Program a copy of this License along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and you
|
||||
may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion of it,
|
||||
thus forming a work based on the Program, and copy and distribute such
|
||||
modifications or work under the terms of Section 1 above, provided that you
|
||||
also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices stating that
|
||||
you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in whole or in
|
||||
part contains or is derived from the Program or any part thereof, to be
|
||||
licensed as a whole at no charge to all third parties under the terms of this
|
||||
License.
|
||||
|
||||
c) If the modified program normally reads commands interactively when run,
|
||||
you must cause it, when started running for such interactive use in the most
|
||||
ordinary way, to print or display an announcement including an appropriate
|
||||
copyright notice and a notice that there is no warranty (or else, saying that
|
||||
you provide a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this License.
|
||||
(Exception: if the Program itself is interactive but does not normally print such
|
||||
an announcement, your work based on the Program is not required to print
|
||||
an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If identifiable
|
||||
sections of that work are not derived from the Program, and can be
|
||||
reasonably considered independent and separate works in themselves, then
|
||||
this License, and its terms, do not apply to those sections when you distribute
|
||||
them as separate works. But when you distribute the same sections as part
|
||||
of a whole which is a work based on the Program, the distribution of the
|
||||
whole must be on the terms of this License, whose permissions for other
|
||||
licensees extend to the entire whole, and thus to each and every part
|
||||
regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest your rights to
|
||||
work written entirely by you; rather, the intent is to exercise the right to
|
||||
control the distribution of derivative or collective works based on the
|
||||
Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of a
|
||||
storage or distribution medium does not bring the other work under the scope
|
||||
of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it, under
|
||||
Section 2) in object code or executable form under the terms of Sections 1
|
||||
and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable source
|
||||
code, which must be distributed under the terms of Sections 1 and 2 above
|
||||
on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three years, to give
|
||||
any third party, for a charge no more than your cost of physically performing
|
||||
source distribution, a complete machine-readable copy of the corresponding
|
||||
source code, to be distributed under the terms of Sections 1 and 2 above on
|
||||
a medium customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer to distribute
|
||||
corresponding source code. (This alternative is allowed only for
|
||||
noncommercial distribution and only if you received the program in object
|
||||
code or executable form with such an offer, in accord with Subsection b
|
||||
above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source code
|
||||
means all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation and
|
||||
installation of the executable. However, as a special exception, the source
|
||||
code distributed need not include anything that is normally distributed (in
|
||||
either source or binary form) with the major components (compiler, kernel,
|
||||
and so on) of the operating system on which the executable runs, unless that
|
||||
component itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering access to
|
||||
copy from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place counts as distribution of the source code,
|
||||
even though third parties are not compelled to copy the source along with the
|
||||
object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program except as
|
||||
expressly provided under this License. Any attempt otherwise to copy,
|
||||
modify, sublicense or distribute the Program is void, and will automatically
|
||||
terminate your rights under this License. However, parties who have received
|
||||
copies, or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not signed it.
|
||||
However, nothing else grants you permission to modify or distribute the
|
||||
Program or its derivative works. These actions are prohibited by law if you
|
||||
do not accept this License. Therefore, by modifying or distributing the
|
||||
Program (or any work based on the Program), you indicate your acceptance
|
||||
of this License to do so, and all its terms and conditions for copying,
|
||||
distributing or modifying the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the original
|
||||
licensor to copy, distribute or modify the Program subject to these terms and
|
||||
conditions. You may not impose any further restrictions on the recipients'
|
||||
exercise of the rights granted herein. You are not responsible for enforcing
|
||||
compliance by third parties to this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues), conditions
|
||||
are imposed on you (whether by court order, agreement or otherwise) that
|
||||
contradict the conditions of this License, they do not excuse you from the
|
||||
conditions of this License. If you cannot distribute so as to satisfy
|
||||
simultaneously your obligations under this License and any other pertinent
|
||||
obligations, then as a consequence you may not distribute the Program at all.
|
||||
For example, if a patent license would not permit royalty-free redistribution
|
||||
of the Program by all those who receive copies directly or indirectly through
|
||||
you, then the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply and
|
||||
the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any patents or
|
||||
other property right claims or to contest validity of any such claims; this
|
||||
section has the sole purpose of protecting the integrity of the free software
|
||||
distribution system, which is implemented by public license practices. Many
|
||||
people have made generous contributions to the wide range of software
|
||||
distributed through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing to
|
||||
distribute software through any other system and a licensee cannot impose
|
||||
that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to be a
|
||||
consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in certain
|
||||
countries either by patents or by copyrighted interfaces, the original copyright
|
||||
holder who places the Program under this License may add an explicit
|
||||
geographical distribution limitation excluding those countries, so that
|
||||
distribution is permitted only in or among countries not thus excluded. In such
|
||||
case, this License incorporates the limitation as if written in the body of this
|
||||
License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will be
|
||||
similar in spirit to the present version, but may differ in detail to address new
|
||||
problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program specifies
|
||||
a version number of this License which applies to it and "any later version",
|
||||
you have the option of following the terms and conditions either of that
|
||||
version or of any later version published by the Free Software Foundation. If
|
||||
the Program does not specify a version number of this License, you may
|
||||
choose any version ever published by the Free Software Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free programs
|
||||
whose distribution conditions are different, write to the author to ask for
|
||||
permission. For software which is copyrighted by the Free Software
|
||||
Foundation, write to the Free Software Foundation; we sometimes make
|
||||
exceptions for this. Our decision will be guided by the two goals of
|
||||
preserving the free status of all derivatives of our free software and of
|
||||
promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
|
||||
PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
|
||||
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
|
||||
WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
|
||||
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
|
||||
NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
|
||||
AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
|
||||
ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
|
||||
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
|
||||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
|
||||
OR DATA BEING RENDERED INACCURATE OR LOSSES
|
||||
SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
|
||||
PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
|
||||
IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,9 @@
|
|||
$Id$
|
||||
|
||||
Description:
|
||||
------------
|
||||
This is the Flukso theme, based on Denis Polevoi's teleology theme.
|
||||
|
||||
Authors:
|
||||
--------
|
||||
icarus75 a.k.a. Bart Van Der Meerssche
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
// $Id: comment.tpl.php,v 1.5 2008/11/23 22:16:19 shannonlucas Exp $
|
||||
|
||||
$comment_class = 'comment' . (($comment->new) ? ' comment-new' : '') .
|
||||
' ' . $status . ' ' . $zebra;
|
||||
?>
|
||||
<div class="<?php print $comment_class; ?>">
|
||||
<div class="content">
|
||||
<?php if (!empty($picture)) { print $picture; } ?>
|
||||
<?php if ($comment->new): ?>
|
||||
<span class="new"><?php print $new ?></span>
|
||||
<?php endif; ?>
|
||||
<?php print $content ?>
|
||||
<div class="clear"></div>
|
||||
<?php if ($signature): ?>
|
||||
<div class="user-signature clear-block">
|
||||
<?php print $signature ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<div class="comment-meta">
|
||||
<span><strong><?php print $author; ?></strong> | <?php print $date; ?></span>
|
||||
<?php if ($links) { print $links; } ?>
|
||||
</div>
|
||||
</div>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,23 @@
|
|||
; $Id:$
|
||||
; --------------------------------------------------------------------------
|
||||
; Basic information about the theme.
|
||||
; --------------------------------------------------------------------------
|
||||
name = Flukso
|
||||
description = "Fixed width theme derived from the Teleology theme"
|
||||
screenshot = screenshot.png
|
||||
core = 6.x
|
||||
engine = phptemplate
|
||||
|
||||
; --------------------------------------------------------------------------
|
||||
; Theme features.
|
||||
; --------------------------------------------------------------------------
|
||||
features[] = name
|
||||
features[] = slogan
|
||||
features[] = search
|
||||
features[] = favicon
|
||||
features[] = primary_links
|
||||
features[] = secondary_links
|
||||
features[] = mission
|
||||
features[] = node_user_picture
|
||||
features[] = comment_user_picture
|
||||
features[] = logo
|
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 691 B |
After Width: | Height: | Size: 777 B |
After Width: | Height: | Size: 108 B |
After Width: | Height: | Size: 106 B |
After Width: | Height: | Size: 194 B |
After Width: | Height: | Size: 501 B |
After Width: | Height: | Size: 641 B |
After Width: | Height: | Size: 712 B |
After Width: | Height: | Size: 804 B |
After Width: | Height: | Size: 862 B |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,22 @@
|
|||
<div class="node<?php print ($sticky) ? " sticky" : ""; ?>">
|
||||
|
||||
<?php if ($page == 0): ?>
|
||||
<h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
|
||||
<?php else: ?>
|
||||
<?php print $picture ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($submitted): ?>
|
||||
<span class="submitted"><?php print t('!date — !username', array('!username' => theme('username', $node), '!date' => format_date($node->created))); ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="content"><?php print $content ?></div>
|
||||
|
||||
<?php if ($links): ?>
|
||||
<em class="clear links">>> <?php print $links ?></em>
|
||||
<?php endif; ?>
|
||||
<?php if ($page == 1): ?>
|
||||
<em class="clear terms"><?php print $terms ?></em>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language->language ?>" xml:lang="<?php print $language->language ?>">
|
||||
<head>
|
||||
<title><?php print $head_title ?></title>
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<?php print $head ?>
|
||||
<?php print $styles ?>
|
||||
<?php print $scripts ?>
|
||||
</head>
|
||||
|
||||
<body <?php print theme("onload_attribute"); ?>>
|
||||
<div id="container">
|
||||
<div id="top">
|
||||
<div id="home">
|
||||
<?php if ($logo) { ?><a id="logo" href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><img src="<?php print $logo ?>" alt="<?php print t('Home') ?>"/></a><?php } ?>
|
||||
<?php if ($site_slogan) { ?><div class="site-slogan"><?php print $site_slogan ?></div><?php } ?>
|
||||
</div>
|
||||
<div id="navigation">
|
||||
<?php if (isset($primary_links)) { ?><div id="primary"><?php print theme('links', $primary_links) ?></div><?php } ?>
|
||||
<?php if (isset($secondary_links)) { ?><div id="secondary"><?php print theme('links', $secondary_links) ?></div><?php } ?>
|
||||
</div>
|
||||
<!-- <div> ?php print $search_box ? </div> -->
|
||||
<br />
|
||||
</div>
|
||||
<?php if ($left) { ?> <div id="leftnav"><?php print $left ?></div> <?php } ?>
|
||||
<?php if ($right) { ?> <div id="rightnav"><?php print $right ?></div> <?php } ?>
|
||||
<div id="content">
|
||||
<!-- print $breadcrumb ?> -->
|
||||
<?php if ($header != ""): ?><div id="header"><?php print $header ?></div><?php endif; ?>
|
||||
<?php if ($title != ""): ?><h2 class="content-title"><?php print $title ?></h2><?php endif; ?>
|
||||
<?php if ($tabs != ""): ?><?php print $tabs ?><?php endif; ?>
|
||||
<?php if ($mission != ""): ?><div id="mission"><?php print $mission ?></div><?php endif; ?>
|
||||
<?php if ($help != ""): ?><p id="help"><?php print $help ?></p><?php endif; ?>
|
||||
<?php if ($messages != ""): ?><div id="message"><?php print $messages ?></div><?php endif; ?>
|
||||
<!-- start main content --><?php print($content) ?><!-- end main content -->
|
||||
</div>
|
||||
<div id="footer"><?php print $footer_message;?><p>Flukso - community metering. Flukso is a project of the <a href="http://www.jokamajo.org">Jokamajo Institute</a>.</p></div>
|
||||
</div>
|
||||
<?php print $closure;?>
|
||||
</body>
|
||||
</html>
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 5.4 KiB |
|
@ -0,0 +1,517 @@
|
|||
/* Flukso theme by icarus75 */
|
||||
/* derived from the teleology theme */
|
||||
|
||||
/* $Id* */
|
||||
|
||||
a {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: rgb(150,150,150);
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: rgb(150,150,150);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background-color:
|
||||
rgb(0,174,239);
|
||||
color: rgb(255,255,255);
|
||||
}
|
||||
|
||||
body {
|
||||
background: #fff;
|
||||
color: #444;
|
||||
font-family: Arial, system, Tahoma, sans-serif;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin: 15px auto;
|
||||
width: 920px;
|
||||
padding 0 10px 10px;
|
||||
}
|
||||
|
||||
#top {
|
||||
background: #f3f3f3;
|
||||
border: 1px solid #ddd;
|
||||
margin: 0 0 12px;
|
||||
width: 684px;
|
||||
}
|
||||
|
||||
#home a:hover {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
#logo img {
|
||||
margin: 1em auto 1em 1em;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.site-name {
|
||||
font-size: 1.8em;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.site-slogan {
|
||||
font-size: .8em;
|
||||
padding: 0em 0em 0em 1em;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
background: #f3f3f3 url(images/menu-bg.png) center repeat;
|
||||
/*border-top: 1px solid #ddd;*/
|
||||
float: left; font-size: 1em;
|
||||
text-align: center; width: 100%;
|
||||
}
|
||||
|
||||
#search {
|
||||
background: #f3f3f3 url(images/menu-bg.png) center repeat;
|
||||
padding-right: .4em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#search .form-text {
|
||||
border-width: 1px;
|
||||
font-size: .6em;
|
||||
}
|
||||
|
||||
#search .form-submit {
|
||||
border-width: 1px;
|
||||
font-size: .6em;
|
||||
}
|
||||
|
||||
#leftnav {
|
||||
float: left;
|
||||
width: 222px;
|
||||
margin: 0 auto auto 0;
|
||||
}
|
||||
|
||||
#rightnav {
|
||||
float: right;
|
||||
width: 222px;
|
||||
margin: 0 0 auto auto;
|
||||
}
|
||||
|
||||
#leftnav .block, #rightnav .block {
|
||||
background: #f3f3f3;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 0.8em;
|
||||
margin: 0% 0 6% 0;
|
||||
}
|
||||
|
||||
#content {
|
||||
background: #f3f3f3;
|
||||
border: 1px solid #ddd;
|
||||
font-size: .8em;
|
||||
width: 660px;
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* :BVDM: center charts in text body */
|
||||
#chart {
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#header .block {
|
||||
border: 1px solid #ddd;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#header .content {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.content-title {
|
||||
font-size: 1.4em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.node {
|
||||
/* border: 1px solid #ddd; */
|
||||
font-size: 1em;
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
font-size: 1em;
|
||||
padding: 0 0 .2em 0;
|
||||
}
|
||||
|
||||
/* forms */
|
||||
.form-item {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* .form-item label { color: #000;} */
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
input, textarea, select {
|
||||
border: 1px silver inset;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
border: 1px #ddd outset;
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
input[type="text"], textarea, input.form-password {
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.node h2 {
|
||||
/* background: #f3f3f3; */
|
||||
color: #f7f7f7;
|
||||
font-size: 1.6em;
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
|
||||
.node .content, .node .info {
|
||||
background: #f3f3f3;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.node .picture {
|
||||
border: 1px solid #ddd;
|
||||
float: right;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.node.item-listing {
|
||||
padding: 1em;
|
||||
border-top: 1px solid #ff0000;
|
||||
}
|
||||
|
||||
.node.item-listing.sticky {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.node table ul {
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.node.sticky .title {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.node .title {
|
||||
border-bottom: 1px solid #ff0000;
|
||||
}
|
||||
|
||||
.messages {
|
||||
background: #eee;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.clear.links {
|
||||
font-size: 1em;
|
||||
padding: 0em;
|
||||
}
|
||||
|
||||
br.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.block {
|
||||
margin-bottom: 1em;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.block h2 {
|
||||
background: #f3f3f3 url(images/menu-bg.png) center repeat;
|
||||
color: #444;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
height: auto;
|
||||
padding: .2em;
|
||||
}
|
||||
|
||||
.block .content {
|
||||
font-size: 1em;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.box {
|
||||
/*border: 1px solid #ddd;*/
|
||||
font-size: 1em;
|
||||
padding: 0em 0em 2em 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.box .title {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.quote-author {
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.quote-msg {
|
||||
/* border: 1px solid #ddd; */
|
||||
background-color: #fefefe;
|
||||
font-style: italic;
|
||||
padding: 0em .2em 0 .2em;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: #f3f3f3;
|
||||
border: 1px solid #ddd;
|
||||
color: #aaa;
|
||||
font-size: 0.64em;
|
||||
padding: .2em 0 .2em 0;
|
||||
width: 684px;
|
||||
margin: 12px 0 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* icons */
|
||||
a.read-more,
|
||||
.icon-print,
|
||||
.icon-add-child-page,
|
||||
.icon-calendar,
|
||||
.form-text#edit-name,
|
||||
.form-password#edit-pass,
|
||||
.form-text#edit-pass,
|
||||
.form-text#edit-date {
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
a.read-more {
|
||||
background-image: url("icons/page_white_go.png");
|
||||
}
|
||||
|
||||
.icon-print {
|
||||
background-image: url("icons/printer.png");
|
||||
}
|
||||
|
||||
.icon-add-child-page {
|
||||
background-image: url("icons/page_white_add.png");
|
||||
}
|
||||
|
||||
.icon-calendar {
|
||||
background-image: url("icons/calendar.png");
|
||||
}
|
||||
|
||||
.form-text#edit-name {
|
||||
background-image: url("icons/user.png");
|
||||
}
|
||||
|
||||
.form-password#edit-pass, .form-text#edit-pass {
|
||||
background-image: url("icons/key.png");
|
||||
}
|
||||
|
||||
.form-text#edit-date {
|
||||
background-image: url("icons/calendar.png");
|
||||
}
|
||||
|
||||
/* tables */
|
||||
tr th, tr.light td, tr.dark td, tr.odd td, tr.even td {
|
||||
padding: 0em .2em 0em .2em;
|
||||
}
|
||||
|
||||
tr.light, tr.dark, tr.even, tr.odd {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
tr.light .active, tr.dark .active, tr.even .active, tr.odd .active {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* tr th {border: 1px solid #ddd;} */
|
||||
|
||||
tr.watchdog-user {
|
||||
background-color: #ffd;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-user .active {
|
||||
background-color: #eed;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-content {
|
||||
background-color: #ddf;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-content .active {
|
||||
background-color: #cce;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-page-not-found, tr.watchdog-access-denied {
|
||||
background-color: #dfd;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-page-not-found .active, tr.watchdog-access-denied .active {
|
||||
background-color: #cec;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-error {
|
||||
background-color: #ffc9c9;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-error .active {
|
||||
background-color: #eeb9b9;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
tr.watchdog-menu, tr.watchdog-menu {
|
||||
background-color: #fff;
|
||||
font-size: .7em;
|
||||
}
|
||||
|
||||
/* lists */
|
||||
ul.primary li a:hover {
|
||||
background-color: rgb(0,174,239);
|
||||
color: rgb(255,255,255);
|
||||
}
|
||||
|
||||
ul.secondary a {
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
ul li a:hover {
|
||||
background-color: rgb(0,174,239);
|
||||
color: rgb(255,255,255);
|
||||
}
|
||||
|
||||
html.js fieldset legend a:hover {
|
||||
background-color: rgb(0,174,239);
|
||||
color: rgb(255,255,255);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Image-assist: overruling clear: both to eliminate spacing below img
|
||||
* --------------------------------------------------------------------- */
|
||||
.image-clear {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Comments
|
||||
* --------------------------------------------------------------------- */
|
||||
#comments {
|
||||
margin-top: 0em;
|
||||
margin-bottom: 2em;
|
||||
padding: 0 1.5em 0 1.5em;
|
||||
}
|
||||
|
||||
div.comment {
|
||||
margin: 0 0 2em 0;
|
||||
}
|
||||
|
||||
div.even div.content,
|
||||
div.odd div.content {
|
||||
border: 1px solid #ccc;
|
||||
border-bottom: 0;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
div.comment div.content h3 {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.comment div.content h3 a:link,
|
||||
div.comment div.content h3 a:visited {
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.comment div.content h3 a:hover {
|
||||
color: #ed1a09;
|
||||
}
|
||||
|
||||
div.comment div.content p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.comment img.user-picture {
|
||||
float: left;
|
||||
padding: 0 10px 5px 0;
|
||||
}
|
||||
|
||||
div.comment div.content p+p { margin-top: 1.5em; }
|
||||
|
||||
div.even div.content { background-color: #fff; }
|
||||
|
||||
div.comment-meta {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0.66em 0 0 0;
|
||||
}
|
||||
|
||||
div.comment-meta span {
|
||||
margin-left: 0.66em;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.even div.comment-meta {
|
||||
background: #f3f3f3 url(images/comment-light.gif) no-repeat top left;
|
||||
margin: 0;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.odd {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.odd div.comment-meta {
|
||||
background: #f3f3f3 url(images/comment-dark.gif) no-repeat top left;
|
||||
}
|
||||
|
||||
em.moderation {
|
||||
background-color: #fffbcc;
|
||||
padding: 2px;
|
||||
border: 1px solid #e6db55;
|
||||
}
|
||||
|
||||
#respond { font-weight: normal }
|
||||
|
||||
#comment-form-wrapper { margin: 0 1.5em 0 1.5em; }
|
||||
|
||||
#comments h2.comments,
|
||||
#comments div.box h2 {
|
||||
display: block;
|
||||
font-size: 1.75em;
|
||||
margin-bottom: 0;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
#comments div.box {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#comment-controls {
|
||||
margin: 20px 0;
|
||||
}
|