diff --git a/.gitmodules b/.gitmodules
index 9383a89..60d40bb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "misc/controller/ethersex"]
path = misc/controller/ethersex
url = git://github.com/ethersex/ethersex.git
+[submodule "misc/website"]
+ path = misc/website
+ url = git@github.com:volkszaehler/website.git
diff --git a/README b/README
index dbdf8d1..8422b06 100644
--- a/README
+++ b/README
@@ -18,7 +18,8 @@ volkszaehler.org/
| \_ demo/ Demo Daten zum Import in die Datenbank
|
|_ tools/ Verschiedene Scripts zum Importieren von Daten, Installation, Helper etc.
- \_ tests/ Einfache Testcases für einige Klasses des Backends
+ |_ tests/ Einfache Testcases für einige Klasses des Backends
+ \_ website/ Die Website unter http://volkszaehler.org
Wiki: http://wiki.volkszaehler.org
Other: http://volkszaehler.org
diff --git a/htdocs/favicon.ico b/htdocs/favicon.ico
new file mode 100644
index 0000000..402bd96
Binary files /dev/null and b/htdocs/favicon.ico differ
diff --git a/htdocs/frontend/index.html b/htdocs/frontend/index.html
index 4709868..732c30b 100644
--- a/htdocs/frontend/index.html
+++ b/htdocs/frontend/index.html
@@ -3,6 +3,9 @@
volkszaehler.org - web frontend
+
+
+
@@ -130,7 +133,10 @@
diff --git a/htdocs/frontend/javascripts/frontend.js b/htdocs/frontend/javascripts/frontend.js
index 09bf440..b03d3f5 100644
--- a/htdocs/frontend/javascripts/frontend.js
+++ b/htdocs/frontend/javascripts/frontend.js
@@ -37,19 +37,31 @@ vz.wui.init = function() {
// buttons
$('button, input[type=button],[type=image]').button();
$('button[name=options-save]').click(function() { vz.options.save(); });
- $('#permalink').click(function() { // TODO add uuids
- var u = window.location.protocol + '//' +
+ $('#permalink').click(function() {
+ var uuids = [];
+ var url = window.location.protocol + '//' +
window.location.host +
window.location.pathname +
'?from=' + vz.options.plot.xaxis.min +
'&to=' + vz.options.plot.xaxis.max;
- window.location = u;
+ vz.entities.each(function(entity, parent) {
+ if (entity.active) {
+ uuids.push(entity.uuid);
+ }
+ });
+
+ uuids.unique().each(function(key, value) {
+ url += '&uuid=' + value;
+ });
+
+ window.location = url;
});
$('button[name=entity-add]').click(function() { $('#entity-add').dialog('open'); });
$('#entity-subscribe input[type=button]').click(function() {
try {
vz.uuids.add($('#entity-subscribe input[type=text]').val());
+ vz.uuids.save();
$('#entity-subscribe input[type=text]').val('');
$('#entity-add').dialog('close');
vz.entities.loadDetails();
@@ -80,16 +92,16 @@ vz.wui.init = function() {
// auto refresh
if (vz.options.refresh) {
$('#refresh').attr('checked', true);
- vz.wui.interval = window.setInterval(vz.wui.refresh, vz.options.refreshInterval);
+ vz.wui.timeout = window.setTimeout(vz.wui.refresh, 3000);
}
$('#refresh').change(function() {
if ($(this).attr('checked')) {
vz.options.refresh = true;
- vz.wui.interval = window.setInterval(vz.wui.refresh, vz.options.refreshInterval);
+ vz.wui.timeout = window.setTimeout(vz.wui.refresh, 3000);
}
else {
vz.options.refresh = false;
- window.clearInterval(vz.wui.interval);
+ window.clearTimeout(vz.wui.timeout);
}
});
@@ -155,9 +167,12 @@ vz.wui.initEvents = function() {
*/
vz.wui.refresh = function() {
var delta = vz.options.plot.xaxis.max - vz.options.plot.xaxis.min;
+
vz.options.plot.xaxis.max = new Date().getTime(); // move plot
vz.options.plot.xaxis.min = vz.options.plot.xaxis.max - delta; // move plot
vz.entities.loadData();
+
+ vz.wui.timeout = window.setTimeout(vz.wui.refresh, (delta / 100 < 3000) ? 3000 : delta / 100); // TODO update timeout after zooming
};
/**
@@ -272,9 +287,9 @@ vz.entities.show = function() {
event.data.active = state;
if (entity.type == 'group') {
- entity.children.each(function(entity) {
- $('#entity-' + entity.uuid + ' input[type=checkbox]').attr('checked', state);
- entity.active = state;
+ entity.children.each(function(child) {
+ $('#entity-' + child.uuid + '.child-of-entity-' + entity.uuid + ' input[type=checkbox]').attr('checked', state);
+ child.active = state;
});
}
@@ -312,6 +327,7 @@ vz.entities.show = function() {
.attr('alt', 'delete')
.bind('click', entity, function(event) {
vz.uuids.remove(event.data.uuid);
+ vz.uuids.save();
vz.entities.loadDetails();
})
);
@@ -435,24 +451,26 @@ vz.load = function(context, identifier, data, success) {
/**
* Parse URL GET parameters
*/
-vz.parseUrlVars = function() {
- var vars = $.getUrlVars();
+vz.parseUrlParams = function() {
+ var vars = $.getUrlParams();
for (var key in vars) {
if (vars.hasOwnProperty(key)) {
switch (key) {
case 'uuid': // add optional uuid from url
- try {
- vz.uuids.add(vars[key]);
- } catch (exception) {
- vz.wui.dialogs.exception(exception);
- }
+ var uuids = (typeof vars[key] == 'string') ? [vars[key]] : vars[key]; // handle multiple uuids
+ uuids.each(function(index, uuid) {
+ try { vz.uuids.add(uuid); } catch (exception) { /* ignore exception */ }
+ });
break;
+
case 'from':
vz.options.plot.xaxis.min = parseInt(vars[key]);
break;
+
case 'to':
vz.options.plot.xaxis.max = parseInt(vars[key]);
break;
+
case 'debug':
$.getScript('javascripts/firebug-lite.js');
break;
@@ -512,7 +530,7 @@ vz.wui.dialogs.error = function(error, description, code) {
modal: true,
buttons: {
Ok: function() {
- $( this ).dialog( "close" );
+ $(this).dialog('close');
}
}
});
diff --git a/htdocs/frontend/javascripts/helper.js b/htdocs/frontend/javascripts/helper.js
index b4c40a0..20ff51a 100644
--- a/htdocs/frontend/javascripts/helper.js
+++ b/htdocs/frontend/javascripts/helper.js
@@ -55,8 +55,9 @@ var Exception = function(type, message, code) {
* according to js language specification ECMA 1.6
*/
Array.prototype.indexOf = function(n) {
- for (var i = 0, l = this.length; i < l; i++)
+ for (var i = 0, l = this.length; i < l; i++) {
if (n == this[i]) return i;
+ }
};
Array.prototype.remove = function(n) {
@@ -64,8 +65,9 @@ Array.prototype.remove = function(n) {
};
Array.prototype.each = function(cb) {
- for (var i = 0, l = this.length; i < l; i++)
+ for (var i = 0, l = this.length; i < l; i++) {
cb(i, this[i]);
+ }
};
Array.prototype.contains = function(n) {
@@ -75,3 +77,13 @@ Array.prototype.contains = function(n) {
Array.prototype.clear = function() {
this.length = 0;
}
+
+Array.prototype.unique = function () {
+ var r = new Array();
+ this.each(function(key, value) {
+ if (!r.contains(value)) {
+ r.push(value);
+ }
+ });
+ return r;
+}
diff --git a/htdocs/frontend/javascripts/init.js b/htdocs/frontend/javascripts/init.js
index 26d3dbf..81e3ded 100644
--- a/htdocs/frontend/javascripts/init.js
+++ b/htdocs/frontend/javascripts/init.js
@@ -63,7 +63,7 @@ $(document).ready(function() {
vz.definitions.load();
vz.uuids.load();
vz.options.load();
- vz.parseUrlVars();
+ vz.parseUrlParams();
// initialize user interface
vz.wui.init();
diff --git a/htdocs/frontend/javascripts/jquery/jquery-extensions.js b/htdocs/frontend/javascripts/jquery/jquery-extensions.js
index e2978cc..c461e0c 100644
--- a/htdocs/frontend/javascripts/jquery/jquery-extensions.js
+++ b/htdocs/frontend/javascripts/jquery/jquery-extensions.js
@@ -29,18 +29,28 @@
* Get URL parameters
*/
$.extend( {
- getUrlVars : function() {
- var vars = [], hash;
+ getUrlParams : function() {
+ var vars = {}, hash;
var hashes = window.location.href.slice(
window.location.href.indexOf('?') + 1).split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
- vars[hash[0]] = hash[1];
+ switch (typeof vars[hash[0]]) {
+ case 'undefined':
+ vars[hash[0]] = hash[1];
+ break;
+
+ case 'string':
+ vars[hash[0]] = Array(vars[hash[0]]);
+
+ case 'object':
+ vars[hash[0]].push(hash[1]);
+ }
}
return vars;
},
- getUrlVar : function(name) {
- return $.getUrlVars()[name];
+ getUrlParam : function(name) {
+ return $.getUrlParams()[name];
}
});
diff --git a/htdocs/frontend/javascripts/options.js b/htdocs/frontend/javascripts/options.js
index b3d5a42..f61cf10 100644
--- a/htdocs/frontend/javascripts/options.js
+++ b/htdocs/frontend/javascripts/options.js
@@ -32,9 +32,8 @@ vz.options = {
rounding: 1,
render: 'lines',
refresh: false,
- refreshInterval: 5*1000, // 5 secs
defaultInterval: 24*60*60*1000, // 1 day
- timezoneOffset: -(new Date().getTimezoneOffset() * 60*1000) // TODO add option with timezone dropdown
+ timezoneOffset: -(new Date().getTimezoneOffset() * 60000) // TODO add option with timezone dropdown
};
vz.options.plot = {
diff --git a/htdocs/frontend/javascripts/uuid.js b/htdocs/frontend/javascripts/uuid.js
index b343b22..2e5cf99 100644
--- a/htdocs/frontend/javascripts/uuid.js
+++ b/htdocs/frontend/javascripts/uuid.js
@@ -31,7 +31,6 @@ vz.uuids.add = function(uuid) {
if (this.validate(uuid)) {
if (!this.contains(uuid)) {
this.push(uuid);
- this.save();
}
else {
throw new Exception('UUIDException', 'UUID already added: ' + uuid);
@@ -48,7 +47,6 @@ vz.uuids.add = function(uuid) {
vz.uuids.remove = function(uuid) {
if (this.contains(uuid)) {
this.splice(this.indexOf(uuid), 1); // remove uuid from array
- this.save();
}
else {
throw new Exception('UUIDException', 'UUID unkown: ' + uuid);
@@ -66,7 +64,8 @@ vz.uuids.validate = function(uuid) {
* Save uuids as cookie
*/
vz.uuids.save = function() {
- $.setCookie('vz_uuids', this.join(';'));
+ var expires = new Date(new Date().getTime() + 31536e6); // expires in a year
+ $.setCookie('vz_uuids', this.join(';'), {expires: expires});
};
/**
diff --git a/lib/Controller/AggregatorController.php b/lib/Controller/AggregatorController.php
index 6aa543f..807f4b7 100644
--- a/lib/Controller/AggregatorController.php
+++ b/lib/Controller/AggregatorController.php
@@ -37,7 +37,7 @@ class AggregatorController extends EntityController {
/**
* Get aggregator
*/
- public function get($identifier) {
+ public function get($identifier = NULL) {
$aggregator = parent::get($identifier);
if ($aggregator instanceof Model\Aggregator) {
diff --git a/lib/Controller/ChannelController.php b/lib/Controller/ChannelController.php
index ade8a6c..6864cde 100644
--- a/lib/Controller/ChannelController.php
+++ b/lib/Controller/ChannelController.php
@@ -37,7 +37,7 @@ class ChannelController extends EntityController {
/**
* Get channel
*/
- public function get($identifier) {
+ public function get($identifier = NULL) {
$channel = parent::get($identifier);
if ($channel instanceof Model\Channel) {
diff --git a/lib/Controller/DataController.php b/lib/Controller/DataController.php
index 6c76d45..e786680 100644
--- a/lib/Controller/DataController.php
+++ b/lib/Controller/DataController.php
@@ -70,18 +70,9 @@ class DataController extends Controller {
public function run($operation, array $identifiers = array()) {
$ec = new EntityController($this->view, $this->em);
+ $entity = $ec->get($identifiers[0]);
- if (count($identifiers) == 2) { // prototype: backend/data/uuid/port.json
- $identifiers[0] = $ec->filter(array(
- 'cuuid' => $identifiers[0],
- 'port' => $identifiers[1]
- ));
- }
- elseif (count($identifiers) == 1) { // assume UUID
- $identifiers[0] = $ec->get($identifiers[0]);
- }
-
- return parent::run($operation, $identifiers);
+ return $this->{$operation}($entity);
}
}
diff --git a/lib/Controller/EntityController.php b/lib/Controller/EntityController.php
index e03fde4..ded0dec 100644
--- a/lib/Controller/EntityController.php
+++ b/lib/Controller/EntityController.php
@@ -34,28 +34,34 @@ use Volkszaehler\Model;
* @package default
*/
class EntityController extends Controller {
+
/**
* Get entity
*
* @param string $identifier
*/
- public function get($uuid) {
- if (!Util\UUID::validate($uuid)) {
- throw new \Exception('Invalid UUID: ' . $uuid);
+ public function get($uuid = NULL) {
+ if (isset($uuid)) {
+ if (!Util\UUID::validate($uuid)) {
+ throw new \Exception('Invalid UUID: ' . $uuid);
+ }
+
+ $dql = 'SELECT a, p
+ FROM Volkszaehler\Model\Entity a
+ LEFT JOIN a.properties p
+ WHERE a.uuid = :uuid';
+
+ $q = $this->em->createQuery($dql);
+ $q->setParameter('uuid', $uuid);
+
+ try {
+ return $q->getSingleResult();
+ } catch (\Doctrine\ORM\NoResultException $e) {
+ throw new \Exception('No entity found with UUID: ' . $uuid, 404);
+ }
}
-
- $dql = 'SELECT a, p
- FROM Volkszaehler\Model\Entity a
- LEFT JOIN a.properties p
- WHERE a.uuid = ?1';
-
- $q = $this->em->createQuery($dql);
- $q->setParameter(1, $uuid);
-
- try {
- return $q->getSingleResult();
- } catch (\Doctrine\ORM\NoResultException $e) {
- throw new \Exception('No entity found with UUID: ' . $uuid, 404);
+ else { // get public entities
+ return $this->filter(array('public' => TRUE));
}
}
@@ -82,49 +88,40 @@ class EntityController extends Controller {
/**
* Adds an entity to the uuids cookie
+ *
+ * @todo add to Model\Entity?
* @param Model\Entity $entity
*/
protected function setCookie(Model\Entity $entity) {
- if ($uuids = $this->view->request->getParameter('uuids', 'cookies')) {
- $uuids = Util\JSON::decode($uuids);
- }
- else {
- $uuids = new Util\JSON();
- }
+ $uuids = ($uuids = $this->view->request->getParameter('vz_uuids', 'cookies')) ? explode(';', $uuids) : array();
// add new UUID
- $uuids->append($entity->getUuid());
-
- // remove duplicates
- $uuids->exchangeArray(array_unique($uuids->getArrayCopy()));
+ $uuids[] = $entity->getUuid();
// send new cookie to browser
- setcookie('uuids', $uuids->encode(), 0, '/'); // TODO correct path
+ setcookie('vz_uuids', implode(';', array_unique($uuids)), 0, '/'); // TODO correct path
}
/**
* Removes an entity from the uuids cookie
+ *
* @param Model\Entity $entity
+ * @todo add to Model\Entity?
*/
protected function unsetCookie(Model\Entity $entity) {
- if ($uuids = $this->view->request->getParameter('uuids', 'cookies')) {
- $uuids = Util\JSON::decode($uuids);
- }
- else {
- $uuids = new Util\JSON();
- }
+ $uuids = ($uuids = $this->view->request->getParameter('vz_uuids', 'cookies')) ? explode(';', $uuids) : array();
// remove old UUID
- $uuids->exchangeArray(array_filter($uuids->getArrayCopy, function($uuid) use ($entity) {
+ $uuids = array_filter($uuids, function($uuid) use ($entity) {
return $uuid != $entity->getUuid();
- }));
+ });
// send new cookie to browser
- setcookie('uuids', $uuids->encode(), 0, '/'); // TODO correct path
+ setcookie('vz_uuids', implode(';', array_unique($uuids)), 0, '/'); // TODO correct path
}
/**
- * Update/set/delete properties of properties
+ * Update/set/delete properties of entities
*/
protected function setProperties(Model\Entity $entity, $parameters) {
foreach ($parameters as $parameter => $value) {
@@ -141,14 +138,19 @@ class EntityController extends Controller {
/**
* Filter entites by properties
+ *
+ * @todo improve performance
+ * @param array of property => value filters
+ * @return array of entities
*/
public function filter(array $properties) {
$dql = 'SELECT a, p
FROM Volkszaehler\Model\Entity a
LEFT JOIN a.properties p';
- $sqlWhere = array();
$i = 0;
+ $sqlWhere = array();
+ $sqlParams = array();
foreach ($properties as $property => $value) {
switch (Definition\PropertyDefinition::get($property)->getType()) {
case 'string':
@@ -158,9 +160,13 @@ class EntityController extends Controller {
break;
case 'boolean':
- $value = ($value) ? 1 : 0;
+ $value = (int) $value;
}
- $sqlWhere[] = 'EXISTS (SELECT p' . $i . ' FROM \Volkszaehler\Model\Property p' . $i . ' WHERE p' . $i . '.name = \'' . $property . '\' AND p' . $i . '.value = ' . $value . ' AND p' . $i . '.entity = a)';
+ $sqlWhere[] = 'EXISTS (SELECT p' . $i . ' FROM \Volkszaehler\Model\Property p' . $i . ' WHERE p' . $i . '.key = :key' . $i . ' AND p' . $i . '.value = :value' . $i . ' AND p' . $i . '.entity = a)';
+ $sqlParams += array(
+ 'key' . $i => $property,
+ 'value' . $i => $value
+ );
$i++;
}
@@ -169,7 +175,7 @@ class EntityController extends Controller {
}
$q = $this->em->createQuery($dql);
- return $q->getSingleResult();
+ return $q->execute($sqlParams);
}
}
diff --git a/lib/Interpreter/Interpreter.php b/lib/Interpreter/Interpreter.php
index 092b001..55088f4 100644
--- a/lib/Interpreter/Interpreter.php
+++ b/lib/Interpreter/Interpreter.php
@@ -56,7 +56,7 @@ abstract class Interpreter implements InterpreterInterface {
*/
public function __construct(Model\Channel $channel, ORM\EntityManager $em, $from, $to) {
$this->channel = $channel;
-
+
// get dbal connection from EntityManager
$this->conn = $em->getConnection();
diff --git a/lib/Model/Entity.php b/lib/Model/Entity.php
index e7c6a02..b6ac43b 100644
--- a/lib/Model/Entity.php
+++ b/lib/Model/Entity.php
@@ -23,12 +23,10 @@
namespace Volkszaehler\Model;
-use Volkszaehler\Definition;
-
use Doctrine\ORM;
-
use Doctrine\Common\Collections;
use Volkszaehler\Util;
+use Volkszaehler\Definition;
/**
* Entity superclass for all objects referenced by a UUID
@@ -124,12 +122,17 @@ abstract class Entity {
* @return array
*/
public function getProperties($prefix = NULL) {
+ /*$this->properties->filter(function($property) {
+ return substr($property->getKey(), 0, strlen($prefix)) == $prefix;
+ })->toArray();*/
+
$properties = array();
foreach ($this->properties as $property) {
if (substr($property->getKey(), 0, strlen($prefix)) == $prefix) {
$properties[$property->getKey()] = $property->getValue();
}
}
+
return $properties;
}
@@ -175,8 +178,9 @@ abstract class Entity {
}
/*
- * Setter & Getter
+ * Setter & getter
*/
+
public function getId() { return $this->id; } // read only
public function getUuid() { return $this->uuid; } // read only
public function getType() { return $this->type; } // read only
diff --git a/lib/Model/Property.php b/lib/Model/Property.php
index 9c0391b..24011ec 100644
--- a/lib/Model/Property.php
+++ b/lib/Model/Property.php
@@ -24,7 +24,6 @@
namespace Volkszaehler\Model;
use Volkszaehler\Definition;
-
use Volkszaehler\Util;
use Volkszaehler\Model;
@@ -73,7 +72,6 @@ class Property {
*/
public function __construct(Model\Entity $entity, $key, $value) {
$this->entity = $entity;
-
$this->key = $key;
$this->value = $value;
}
@@ -118,6 +116,7 @@ class Property {
/**
* @PreRemove
+ * @todo blocks removal of entity
*/
public function checkRemove() {
if (in_array($this->key, $this->entity->getDefinition()->getRequiredProperties())) {
@@ -135,8 +134,9 @@ class Property {
}
/*
- * Setter & Getter
+ * Setter & getter
*/
+
public function getKey() { return $this->key; }
public function getValue() { return $this->value; }
public function getDefinition() { return Definition\PropertyDefinition::get($this->key); }
diff --git a/lib/Router.php b/lib/Router.php
index 520377d..1e14550 100644
--- a/lib/Router.php
+++ b/lib/Router.php
@@ -137,7 +137,7 @@ class Router {
/**
* Processes the request
*
- * Example: http://sub.domain.local/vz/backend/channel/550e8400-e29b-11d4-a716-446655440000/data.json?operation=edit&title=New Title
+ * Example: http://sub.domain.local/backend.php/channel/550e8400-e29b-11d4-a716-446655440000/data.json?operation=edit&title=New Title
*/
public function run() {
$operation = self::getOperation($this->view->request);
diff --git a/lib/Util/Debug.php b/lib/Util/Debug.php
index 81f2273..9503c99 100644
--- a/lib/Util/Debug.php
+++ b/lib/Util/Debug.php
@@ -85,10 +85,10 @@ class Debug {
self::$instance->messages[] = array(
'message' => $message,
- //'file' => $info['file'],
- //'line' => $info['line'],
+ 'file' => $info['file'],
+ 'line' => $info['line'],
//'time' => date('r'),
- 'args' => array_slice($info['args'], 1),
+ 'args' => array_slice($info['args'], 1)
//'trace' => array_slice($trace, 1)
);
}
diff --git a/misc/controller/ethersex b/misc/controller/ethersex
index 822c9dc..64a3546 160000
--- a/misc/controller/ethersex
+++ b/misc/controller/ethersex
@@ -1 +1 @@
-Subproject commit 822c9dce3a2c13de28af0080aa39e166831e19b1
+Subproject commit 64a3546f9ba8a0a4070f8b6ecc182643d5539699
diff --git a/misc/graphics/backend.dia b/misc/graphics/backend.dia
new file mode 100644
index 0000000..092df86
Binary files /dev/null and b/misc/graphics/backend.dia differ
diff --git a/misc/graphics/backend.png b/misc/graphics/backend.png
new file mode 100644
index 0000000..b4e9157
Binary files /dev/null and b/misc/graphics/backend.png differ
diff --git a/misc/graphics/favicon.ico b/misc/graphics/favicon.ico
new file mode 100644
index 0000000..402bd96
Binary files /dev/null and b/misc/graphics/favicon.ico differ
diff --git a/misc/graphics/favicon.png b/misc/graphics/favicon.png
new file mode 100644
index 0000000..5a8c62e
Binary files /dev/null and b/misc/graphics/favicon.png differ
diff --git a/misc/graphics/favicon.svg b/misc/graphics/favicon.svg
new file mode 100644
index 0000000..ba20a3b
--- /dev/null
+++ b/misc/graphics/favicon.svg
@@ -0,0 +1,89 @@
+
+
+
+
diff --git a/misc/website b/misc/website
new file mode 160000
index 0000000..d542e6a
--- /dev/null
+++ b/misc/website
@@ -0,0 +1 @@
+Subproject commit d542e6a6817f90f01bffb50f481c308d9d0753da