root/branches/fsheedy/wifidog/classes/Node.php @ 1442

Revision 1442, 71.7 KB (checked in by fsheedy, 3 years ago)

Node Bypass abuse dynamic control first draft

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1<?php
2
3/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5// +-------------------------------------------------------------------+
6// | WiFiDog Authentication Server                                     |
7// | =============================                                     |
8// |                                                                   |
9// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
10// | portal suite.                                                     |
11// +-------------------------------------------------------------------+
12// | PHP version 5 required.                                           |
13// +-------------------------------------------------------------------+
14// | Homepage:     http://www.wifidog.org/                             |
15// | Source Forge: http://sourceforge.net/projects/wifidog/            |
16// +-------------------------------------------------------------------+
17// | This program is free software; you can redistribute it and/or     |
18// | modify it under the terms of the GNU General Public License as    |
19// | published by the Free Software Foundation; either version 2 of    |
20// | the License, or (at your option) any later version.               |
21// |                                                                   |
22// | This program is distributed in the hope that it will be useful,   |
23// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
24// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
25// | GNU General Public License for more details.                      |
26// |                                                                   |
27// | You should have received a copy of the GNU General Public License |
28// | along with this program; if not, contact:                         |
29// |                                                                   |
30// | Free Software Foundation           Voice:  +1-617-542-5942        |
31// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
32// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
33// |                                                                   |
34// +-------------------------------------------------------------------+
35
36/**
37 * @package    WiFiDogAuthServer
38 * @author     Benoit Grégoire <bock@step.polymtl.ca>
39 * @copyright  2005-2006 Benoit Grégoire, Technologies Coeus inc.
40 * @version    Subversion $Id$
41 * @link       http://www.wifidog.org/
42 */
43
44/**
45 * Load required classes
46 */
47require_once('classes/User.php');
48require_once('classes/GisPoint.php');
49require_once('classes/AbstractGeocoder.php');
50require_once('classes/Utils.php');
51require_once('classes/DateTimeWD.php');
52require_once('classes/HotspotGraphElement.php');
53
54/**
55 * Abstract a Node.  A Node is an actual physical transmitter.
56 *
57 * @todo Make all the setter functions no-op if the value is the same as what
58 * was already stored Use setCustomPortalReduirectUrl as an example
59 *
60 * @package    WiFiDogAuthServer
61 * @author     Benoit Grégoire <bock@step.polymtl.ca>
62 * @copyright  2005 Benoit Grégoire, Technologies Coeus inc.
63 */
64class Node extends HotspotGraphElement
65{
66    /** Object cache for the object factory (getObject())*/
67    protected $_row;
68    protected $mdB; /**< An AbstractDb instance */
69    protected $id;
70    protected static $currentNode = null;
71
72    /**
73     * List of deployment statuses
74     *
75     * @var array
76     * @access private
77     */
78    protected $_deploymentStatuses = array();
79
80    /**
81     * Defines a warning message
82     *
83     * @var string
84     *
85     * @access private
86     */
87    protected $_warningMessage;
88
89    /** Instantiate a node object
90     * @param $id The id of the requested node
91     * @return a Node object, or null if there was an error
92     */
93    public static function &getObject($id)
94    {
95        return HotspotGraphElement::getObject($id, 'Node');
96    }
97
98    /** Free an instanciated object
99     * @param $id The id to free
100     * Thanks and so long for all the ram.
101     */
102    public static function freeObject($id)
103    {
104        HotspotGraphElement::freeObject($id, 'Node');
105    }
106
107    /** Instantiate a node object using it's gateway id
108     * @param $gwId The id of the requested node
109     * @return a Node object, or null if there was an error
110     */
111    static function getObjectByGatewayId($gwId)
112    {
113        $object = null;
114        $object = new self($gwId, 'GATEWAY_ID');
115        return $object;
116    }
117    /** Get the current node for which the portal is displayed or to which a user is physically connected.
118     * @param $real_node_only true or false.  If true, the real physical node where the user is connected is returned, and the node set by setCurrentNode is ignored.
119     * @return a Node object, or null if it can't be found.
120     */
121    static function getCurrentNode($real_node_only = false)
122    {
123        $object = null;
124        if (self :: $currentNode != null && $real_node_only == false)
125        {
126            $object = self :: $currentNode;
127        }
128        else
129        {
130            $object = self :: getCurrentRealNode();
131        }
132        return $object;
133    }
134
135    /** Set the current node where the user is to be considered connected to.  (For portal and content display purposes, among other.
136     * @param $node Node object or null.  The new current node.
137     * @return true      */
138    static function setCurrentNode($node)
139    {
140        if(empty($node) || $node instanceof Node) {
141            self :: $currentNode = $node;
142        }
143        else {
144            throw new Exception(sprintf("Parameter node must be null or of class Node but is of class %s", get_class($node)));
145        }
146        return true;
147    }
148
149    /** Get the current node to which a user is physically connected, if any.  This is done by an IP address lookup against the last reported IP address of the node
150     * @param    * @return a Node object, or null if it can't be found.
151     */
152    public static function getCurrentRealNode()
153    {
154        static $currentRealNode;//For caching
155        static $currentRealNodeComputed;//For caching
156        $currentIp = $_SERVER['REMOTE_ADDR'];
157        //For testing:
158        //$currentIp = '24.201.12.219';
159        if(!isset($currentRealNodeComputed))
160        {
161            //echo "getCurrentTealNode(): Computing for IP $currentIp<br/>";
162            $currentRealNodeComputed=true;
163            $db = AbstractDb::getObject();
164            $sql_ip = "SELECT node_id from nodes WHERE last_heartbeat_ip='$currentIp' ORDER BY last_heartbeat_timestamp DESC";
165            $node_rows = null;
166            $db->execSql($sql_ip, $node_rows, false);
167            $num_match = count($node_rows);
168            if ($num_match == 0)
169            {
170                // User is not physically connected to a node
171                $currentRealNode = null;
172            }
173            else if ($num_match == 1)
174            {
175                // Only a single node matches, the user is presumed to be there
176                $currentRealNode = self::getObject($node_rows[0]['node_id']);
177            }
178            else
179            {
180                /* We have more than one node matching the IP (the nodes are behind the same NAT).*/
181                $currentRealNode = null;
182                $current_user = User :: getCurrentUser();
183                if ($current_user != null)
184                {
185                    /* We will try to discriminate by finding which node the user last authenticated against.
186                     * If the IP matches, we can be pretty certain the user is there.
187                     */
188                    $current_user_id = $current_user->getId();
189                    $sql = "SELECT node_id, last_heartbeat_ip, name, last_updated from connections NATURAL JOIN nodes WHERE user_id='$current_user_id' AND node_id IN ($sql_ip) ORDER BY last_updated DESC ";
190                    //$db->execSql($sql, $tmp, true);
191                    $db->execSqlUniqueRes("$sql LIMIT 1", $node_row, false);
192                    if ($node_row != null)
193                    {
194                        $currentRealNode = self::getObject($node_row['node_id']);
195                    }
196                }
197                else {
198                    /* Darn, the user doesn't have a session open, we can only take the first node in the list, which is marginaly better than nothing */
199                    $currentRealNode = self::getObject($node_rows[0]['node_id']);
200                }
201            }
202        }
203        return $currentRealNode;
204    }
205
206    public function delete(& $errmsg)
207    {
208        $retval = false;
209        $user = User :: getCurrentUser();
210        if ($user->DEPRECATEDisSuperAdmin()) {
211            $db = AbstractDb::getObject();
212            $id = $db->escapeString($this->getId());
213            if (!$db->execSqlUpdate("DELETE FROM nodes WHERE node_id='{$id}'", false))
214            {
215                $errmsg = _('Could not delete node!');
216            }
217            else
218            {
219                parent::_delete($errmsg);
220                $retval = true;
221            }
222        }
223        else
224        {
225            $errmsg = _('Access denied!');
226        }
227
228        return $retval;
229    }
230
231    /**
232     * Create a new Node in the database
233     *
234     * @param string $gw_id The Id of the gatewqay to be associated with
235     * thisnode. If not present, a dummy value will be assigned.
236     * @param object $network Network object.  The node's network.  If not
237     *                        present, the current Network will be assigned
238     *
239     * @return mixed The newly created Node object, or null if there was
240     *               an error
241     *
242     * @static
243     * @access public
244     */
245    public static function createNewObject($gw_id = null, $network = null)
246    {
247        $db = AbstractDb::getObject();
248        if (empty ($gw_id)) {
249            $gw_id = $db->escapeString(_('PUT_GATEWAY_ID_HERE'));
250        }
251        else
252        {
253            $gw_id = $db->escapeString($gw_id);
254        }
255        $node_id = get_guid();
256
257
258        if (empty ($network)) {
259            $network = Network::getCurrentNetwork();
260        }
261
262        $network_id = $db->escapeString($network->getId());
263
264        $node_deployment_status = $db->escapeString("IN_PLANNING");
265        $node_name = _("New node");
266        $duplicate = null;
267        try{
268            $duplicate = Node::getObjectByGatewayId($gw_id);
269        }
270        catch (Exception $e)
271        {
272        }
273        if ($duplicate) {
274            throw new Exception(sprintf(_('Sorry, a node for the gateway %s already exists.'),$gw_id));
275        }
276
277        $sql = "INSERT INTO nodes (node_id, gw_id, network_id, creation_date, node_deployment_status, name) VALUES ('$node_id', '$gw_id', '$network_id', CURRENT_TIMESTAMP,'$node_deployment_status', '$node_name')";
278
279        if (!$db->execSqlUpdate($sql, false)) {
280            throw new Exception(_('Unable to insert new node into database!'));
281        }
282
283        HotspotGraphElement::createNewObject($node_id, 'Node');
284       
285        $object = self::getObject($node_id);
286
287        return $object;
288    }
289
290    /** Get an interface to pick a node.
291     * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form
292     *
293     * @param string $userData=null Array of contextual data optionally sent to the method.
294     *  The function must still function if none of it is present.
295     * This method understands:
296     *  $userData['preSelectedObject'] An optional object to pre-select.
297     *  $userData['additionalWhere'] Additional SQL conditions for the
298     *                                    objects to select
299     *  $userData['additionalJoin'] Additional SQL JOIN conditions for the
300     *                                    objects to select
301     *  $userData['preSelectedObjects'] An optional object or array of objects to pre-select. (not
302     * supported by type_interface=table)
303     *  $userData['typeInterface'] select, select_multiple or table.  Default is "select"
304     *
305     * * @return html markup
306     */
307    public static function getSelectUI($user_prefix, $userData=null)
308    {
309        !empty($userData['additionalJoin'])?$sql_additional_join=$userData['additionalJoin']:$sql_additional_join=null;
310        !empty($userData['additionalWhere'])?$sql_additional_where=$userData['additionalWhere']:$sql_additional_where=null;
311        !empty($userData['preSelectedObjects'])?$selectedNodes=$userData['preSelectedObjects']:$selectedNodes=null;
312        !empty($userData['typeInterface'])?$type_interface=$userData['typeInterface']:$type_interface="select";
313
314        $db = AbstractDb::getObject();
315        $html = '';
316        $name = "{$user_prefix}";
317
318        $_deploymentStatuses = array(
319        "DEPLOYED" => _("Deployed"),
320        "IN_PLANNING" => _("In planning"),
321        "IN_TESTING" => _("In testing"),
322        "NON_WIFIDOG_NODE" => _("Non-Wifidog node"),
323        "PERMANENTLY_CLOSED" => _("Permanently closed"),
324        "TEMPORARILY_CLOSED" => _("Temporarily closed")
325        );
326
327        $sql = "SELECT nodes.node_id, nodes.name, nodes.gw_id, nodes.node_deployment_status, nodes.is_splash_only_node from nodes $sql_additional_join WHERE 1=1 $sql_additional_where ORDER BY lower(nodes.node_id)";
328        $node_rows = null;
329        $db->execSql($sql, $node_rows, false);
330
331        if ($node_rows != null) {
332            Utils :: natsort2d($node_rows, "name");
333            if ($type_interface != "table") {
334                $i = 0;
335                foreach ($node_rows as $node_row)
336                {
337                    $tab[$i][0] = $node_row['node_id'];
338                    //$tab[$i][1] = sprintf(_("%s (gw: %s)"),$node_row['name'],$node_row['gw_id']);
339                    $tab[$i][1] = $node_row['name'];
340                    $i ++;
341                }
342                if($type_interface == "select_multiple"){
343                    $select_options="MULTIPLE SIZE=6";
344                }
345                else
346                {
347                    $select_options=null;
348                }
349                //pretty_print_r($selectedNodes);
350                if(is_array($selectedNodes)){
351                    $selectedPrimaryKey=array();
352                    foreach($selectedNodes as $node){
353                        $selectedPrimaryKey[]=$node->getId();
354                    }
355
356                }
357                else if($selectedNodes instanceof Node){
358                    $selectedPrimaryKey=$selectedNodes->getId();
359                }
360                else{
361                    $selectedPrimaryKey=null;
362                }
363                $html .= FormSelectGenerator :: generateFromArray($tab, $selectedPrimaryKey, $name, null, false, null, $select_options);
364            } else {
365                $html .= "<fieldset>\n    <legend>Node List</legend>\n";
366                $html .= "    <span class='node_admin'>"._("Filter:")."<input type=\"text\" tabindex=\"1\" maxlength=\"40\" size=\"40\" id=\"nodes_list_filter\" name=\"nodes_list_filter\" /></span>\n    <br/>\n";
367                $html .= "    <!--[if IE]><style type='text/css'>#node_list_div table.scrollable>tbody { height: 15px; }</style><![endif]-->\n";
368                $html .= "    <script src='" . BASE_URL_PATH . "js/filtertable.js' type='text/javascript' language='javascript' charset='utf-8'></script>\n";
369                $html .= "    <script src='" . BASE_URL_PATH . "js/sorttable.js' type='text/javascript' language='javascript' charset='utf-8'></script>\n";
370                $html .= "    <div id='node_list_div' class='node_admin tableContainer'>\n";
371                $html .= "        <table id='nodes_list' class='node_admin filterable scrollable sortable'>\n\n";
372                $html .= "            <thead class='fixedHeader'>\n";
373                $html .= "<tr class='nofilter'>\n";
374                $html .= "<th>"._("Node Name")."</th>\n";
375                $html .= "<th>"._("Gateway ID")."</th>\n";
376                $html .= "<th>"._("Deployment Status")."</th>\n";
377                $html .= "</tr>\n";
378                $html .= "</thead>\n";
379                $html .= "<tbody>";
380
381                $i = 0;
382                foreach ($node_rows as $node_row)
383                {
384                    $href = GENERIC_OBJECT_ADMIN_ABS_HREF."?object_id={$node_row['node_id']}&object_class=Node&action=edit";
385                    $_deployStatusNode = $node_row['node_deployment_status'];
386                    $html .= "<tr class='row' onclick=\"javascript:location.href='{$href}'\">\n";
387                    $html .= "<td>{$node_row['name']}<noscript>(<a href='{$href}'>edit</a>)</noscript></td>\n";
388                    $html .= "<td>{$node_row['gw_id']}</td>\n";
389                    $html .= "<td>{$_deploymentStatuses[$_deployStatusNode]}</td>\n";
390                    $html .= "</tr>\n";
391                }
392                $html .= "            </tbody>\n        </table>\n";
393                $html .= "    </div>\n";
394                $html .= "</fieldset>\n";
395
396            }
397        } else {
398            $html .= "<div class='warningmsg'>"._("Sorry, no nodes available in the database")."</div>\n";
399        }
400        return $html;
401    }
402
403
404    /** Get the selected Network object.
405     * @param $user_prefix A identifier provided by the programmer to recognise it's generated form
406     * @return the node object
407     */
408    static function processSelectUI($user_prefix)
409    {
410        $object = null;
411        $name = "{$user_prefix}";
412        return self::getObject($_REQUEST[$name]);
413    }
414
415    /** Get an interface to create a new node.
416     * @param $network Optional:  The network to which the new node will belong,
417     * if absent, the user will be prompted.
418     * @return html markup
419     */
420    public static function getCreateNewObjectUI($network = null)
421    {
422        $html = '';
423        $html .= _("Add a new node for the gateway ID")." \n";
424        $name = "new_node_gw_id";
425        $html .= "<input type='text' size='10' name='{$name}'>\n";
426        if ($network)
427        {
428            $name = "new_node_network_id";
429            $html .= "<input type='hidden' name='{$name}' value='{$network->getId()}'>\n";
430        }
431        else
432        {
433            $html .= " "._("in ")." \n";
434            $html .= Network :: getSelectUI('new_node');
435        }
436        return $html;
437
438    }
439
440    /**
441     * Process the new object interface.
442     *
443     * Will return the new object if the user has the credentials and the form was fully filled.
444     * @return the node object or null if no new node was created.
445     */
446    public static function processCreateNewObjectUI()
447    {
448        // Init values
449        $retval = null;
450        $name = "new_node_gw_id";
451
452        if (!empty ($_REQUEST[$name])) {
453            $gw_id = $_REQUEST[$name];
454        }
455        else
456        {
457            $gw_id = null;
458        }
459        $name = "new_node_network_id";
460
461        if (!empty ($_REQUEST[$name])) {
462            $network = Network::getObject($_REQUEST[$name]);
463        } else {
464            $network = Network::processSelectUI('new_node');
465        }
466
467        if ($network) {
468            Security::requirePermission(Permission::P('NETWORK_PERM_ADD_NODE'), $network);
469            $retval = self::createNewObject($gw_id, $network);
470        }
471
472        return $retval;
473    }
474
475
476    /** Get an interface to deal with missing nodes.  If the user has the permissions, he will be asked to create a new node for that gateway id, or assign that gateway id to an existing node.
477     * @param $gwId The unknown gwId
478     * @return html markup
479     */
480    public static function getStealOrCreateNewUI($gwId)
481    {
482        $permissionArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), null);
483        $permissionArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), null);
484        Security::requireAnyPermission($permissionArray);
485        $db = AbstractDb::getObject();
486        $html = '';
487        $allowedNetworks = Security::getObjectsWithPermission(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'));
488        $allowedNodes = Security::getObjectsWithPermission(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'));
489        $html .= "<p>"._("Here is what you can do to fix this:")."</p>\n";
490        $html .= "<ul>\n";
491        if($allowedNetworks) {
492            //Add a new node for unknown node id
493            $html .= "<li>".sprintf(_("You can create a new node with %s as it's associated gateway id.  This is typical for new installations."), $gwId)."<br/>\n";
494
495            $networkAdditionalWhere=" AND (FALSE\n";
496            foreach ($allowedNetworks as $network) {
497                $idStr = $db->escapeString($network->getId());
498                $networkAdditionalWhere .= " OR network_id='$idStr'\n";
499            }
500            $networkAdditionalWhere .= ")\n";
501            $userData['preSelectedObject']=null;
502            $userData['allowEmpty']=true;
503            $userData['additionalWhere']=$networkAdditionalWhere;
504            $name = "{$gwId}_new_node_network";
505            $networkSelectUI = Network :: getSelectUI($name, $userData);
506            $html .= sprintf(_("Add a new node in %s"), $networkSelectUI)." \n";
507            $name = "{$gwId}_new_node_submit";
508            $value = _("Add node");
509            $html .= "<input type='submit' size='10' name='{$name}' value='$value'>\n";
510            $html .= "</li>\n";
511        }
512
513        if($allowedNetworks || $allowedNodes){
514            //"Steal" an existing node for this ID (typically for hardware replacement)
515            $html .= "<li>".sprintf(_("You can \"steal\" an existing node.  The node's gateway id will be replaced with %s.  This is typical when replacing hardware."), $gwId)."<br/>\n";
516            if($allowedNetworks) {
517                $additionalWhere=$networkAdditionalWhere;
518            }
519            else {
520                $additionalWhere=" AND (FALSE\n";
521                foreach ($allowedNetworks as $network) {
522                    $idStr = $db->escapeString($node->getId());
523                    $additionalWhere .= " OR node_id='$idStr'\n";
524                }
525                $additionalWhere .= ")\n";
526            }
527
528            $userData['preSelectedObject']=null;
529            $userData['allowEmpty']=true;
530            $userData['additionalWhere']=$additionalWhere;
531            $name = "{$gwId}_steal_node";
532            $html .= Node :: getSelectUI($name, $userData);
533            $name = "{$gwId}_steal_node_submit";
534            $value = _("Steal node");
535            $html .= "<input type='submit' size='10' name='{$name}' value='$value'>\n";
536            $html .= "</li>\n";
537        }
538        $html .= "</ul>\n";
539        return $html;
540
541    }
542
543    /**
544     * Process the interface to deal with missing nodes.
545     * @param $gwId The unknown gwId
546     * @param $nodeIsNew Output parameter.  Will be set to true if a new node was created to resolve the situation
547     * @return the created or stolen node object, or null if none was created (or stolen).
548     */
549    public static function processStealOrCreateNewUI($gwId, &$nodeIsNew=null)
550    {
551        // Init values
552        $retval = null;
553        $nodeIsNew = false;
554        $name = "{$gwId}_new_node_submit";
555        if(!empty($_REQUEST[$name])) {
556            //Create new node
557            $name = "{$gwId}_new_node_network";
558            $network = Network :: processSelectUI($name);
559            if($network) {
560                Security::requirePermission(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
561                //echo  _("Adding node");
562                $node = Node::createNewObject($gwId, $network);
563                $nodeIsNew = true;
564                $retval = $node;
565            }
566        }
567        $name = "{$gwId}_steal_node_submit";
568        if(!empty($_REQUEST[$name])){
569            //"Steal" an existing node for this ID (typically for hardware replacement)
570            $name = "{$gwId}_steal_node";
571            $node = Node :: processSelectUI($name);
572            if($node) {
573                $permissionArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $node->getNetwork());
574                $permissionArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $node);
575                Security::requireAnyPermission($permissionArray);
576                //echo _("Stealing node $node");
577                $node->setGatewayId($gwId);
578                $retval = $node;
579            }
580        }
581
582
583        return $retval;
584    }
585
586
587
588    /**
589     * Get an interface to select the deployment status
590     *
591     * @param string $user_prefix A identifier provided by the programmer to
592     *                            recognise it's generated html form
593     *
594     * @return string HTML markup
595     */
596    public function getSelectDeploymentStatus($user_prefix)
597    {
598         
599        $db = AbstractDb::getObject();
600
601        // Init values
602        $html = "";
603        $status_list = null;
604        $tab = array();
605
606        $name = "{$user_prefix}";
607        $db->execSql("SELECT node_deployment_status FROM node_deployment_status", $status_list, false);
608
609        if ($status_list == null) {
610            throw new Exception(_("No deployment statuses could be found in the database"));
611        }
612
613        foreach ($status_list as $status) {
614            $_statusvalue = $status['node_deployment_status'];
615            $tab[] = array($_statusvalue, $this->_deploymentStatuses["$_statusvalue"]);
616        }
617
618        $html .= FormSelectGenerator::generateFromArray($tab, $this->getDeploymentStatus(), $name, null, false);
619
620        return $html;
621    }
622
623    /**
624     * Get the selected deployment status
625     *
626     * @param string $user_prefix An identifier provided by the programmer to
627     *                            recognise it's generated form
628     *
629     * @return string The deployment status
630
631     */
632    public function processSelectDeploymentStatus($user_prefix)
633    {
634        $object = null;
635        $name = "{$user_prefix}";
636        return $_REQUEST[$name];
637    }
638
639    /**
640     * Get the selected network ID
641     *
642     * @param string $user_prefix An identifier provided by the programmer to
643     *                            recognise it's generated form
644     *
645     * @return string The deployment status
646
647     */
648    public function processSelectNetworkId($user_prefix)
649    {
650        $object = null;
651        $name = "{$user_prefix}";
652        return $_REQUEST[$name];
653    }
654
655    /** @param $id The id of the node
656     * @param $idType 'NODE_ID' or 'GATEWAY_ID'*/
657    protected function __construct($id, $idType='NODE_ID')
658    {
659        $db = AbstractDb::getObject();
660        $this->mDb = & $db;
661
662        $id_str = $db->escapeString($id);
663        switch ($idType) {
664            case 'NODE_ID': $sqlWhere = "node_id='$id_str'";
665            break;
666            case 'GATEWAY_ID': $sqlWhere = "gw_id='$id_str'";
667            break;
668            default:
669                throw new exception('Unknown idType parameter');
670        }
671        $sqlWhere =
672        $sql = "SELECT * FROM nodes WHERE $sqlWhere";
673        $row = null;
674        $db->execSqlUniqueRes($sql, $row, false);
675        if ($row == null)
676        {
677            throw new Exception(sprintf(_("The node with %s: %s could not be found in the database!"), $idType, $id_str));
678        }
679
680        $this->_deploymentStatuses = array(
681        "DEPLOYED" => _("Deployed"),
682        "IN_PLANNING" => _("In planning"),
683        "IN_TESTING" => _("In testing"),
684        "NON_WIFIDOG_NODE" => _("Non-Wifidog node"),
685        "PERMANENTLY_CLOSED" => _("Permanently closed"),
686        "TEMPORARILY_CLOSED" => _("Temporarily closed")
687        );
688
689        $this->_row = $row;
690        $this->id = $row['node_id'];
691       
692        parent::__construct($this->id, 'Node');
693    }
694
695    function __toString() {
696        return $this->getName();
697    }
698
699    function getId()
700    {
701        return $this->id;
702    }
703
704    /** Get the id of the gateway associated with this node */
705    function getGatewayId()
706    {
707        return $this->_row['gw_id'];
708    }
709    /** Change the gateway ID of the gateway asociated with this node.
710     * @param $id, string, the new node id.
711     * @return true on success, false on failure. Check this,
712     * as it's possible that someone will enter an existing id, especially
713     * if the MAC address is used and hardware is recycled.
714     */
715    function setGatewayId($id)
716    {
717        $id = $this->mDb->escapeString($id);
718        $retval = $this->mDb->execSqlUpdate("UPDATE nodes SET gw_id = '{$id}' WHERE node_id = '{$this->getId()}'");
719        if ($retval)
720        {
721            $this->refresh();
722        }
723        return $retval;
724    }
725
726    /** Gets the Network to which the node belongs
727     * @return Network object (never returns null)
728     */
729    public function getNetwork()
730    {
731        return Network :: getObject($this->_row['network_id']);
732    }
733
734
735    function setNetwork(Network $network)
736    {
737        $net = $this->mDb->escapeString($network->getId());
738        $this->mDb->execSqlUpdate("UPDATE nodes SET network_id = '{$net}' WHERE node_id = '{$this->getId()}'");
739        $this->refresh();
740    }
741
742
743    /** Get a GisPoint object ; altide is not supported yet
744     */
745    function getGisLocation()
746    {
747        // Altitude is not supported yet
748        return new GisPoint($this->_row['latitude'], $this->_row['longitude'], 0);
749    }
750
751    function setGisLocation($pt)
752    {
753        if (!empty ($pt))
754        {
755            $lat = $this->mDb->escapeString($pt->getLatitude());
756            $long = $this->mDb->escapeString($pt->getLongitude());
757
758            if (!empty ($lat) && !empty ($long))
759                $this->mDb->execSqlUpdate("UPDATE nodes SET latitude = $lat, longitude = $long WHERE node_id = '{$this->getId()}'");
760            else
761                $this->mDb->execSqlUpdate("UPDATE nodes SET latitude = NULL, longitude = NULL WHERE node_id = '{$this->getId()}'");
762            $this->refresh();
763        }
764    }
765
766    /** Return the name of the node
767     */
768    function getName()
769    {
770        return $this->_row['name'];
771    }
772
773    function setName($name)
774    {
775        $name = $this->mDb->escapeString($name);
776        $this->mDb->execSqlUpdate("UPDATE nodes SET name = '{$name}' WHERE node_id = '{$this->getId()}'");
777        $this->refresh();
778    }
779
780    function getCreationDate()
781    {
782        return $this->_row['creation_date'];
783    }
784
785    function setCreationDate($creation_date)
786    {
787        $creation_date = $this->mDb->escapeString($creation_date);
788        $this->mDb->execSqlUpdate("UPDATE nodes SET creation_date = '{$creation_date}' WHERE node_id = '{$this->getId()}'");
789        $this->refresh();
790    }
791
792    function getWebSiteURL()
793    {
794        return $this->_row['home_page_url'];
795    }
796
797    function setWebSiteUrl($url)
798    {
799        $url = $this->mDb->escapeString($url);
800        $this->mDb->execSqlUpdate("UPDATE nodes SET home_page_url = '{$url}' WHERE node_id = '{$this->getId()}'");
801        $this->refresh();
802    }
803
804    function getDescription()
805    {
806        return $this->_row['description'];
807    }
808
809    function setDescription($description)
810    {
811        $description = $this->mDb->escapeString($description);
812        $this->mDb->execSqlUpdate("UPDATE nodes SET description = '{$description}' WHERE node_id = '{$this->getId()}'");
813        $this->refresh();
814    }
815
816    function getMapURL()
817    {
818        return $this->_row['map_url'];
819    }
820
821    function setMapURL($url)
822    {
823        $url = $this->mDb->escapeString($url);
824        $this->mDb->execSqlUpdate("UPDATE nodes SET map_url = '{$url}' WHERE node_id = '{$this->getId()}'");
825        $this->refresh();
826    }
827
828    public function getCivicNumber()
829    {
830        return $this->_row['civic_number'];
831    }
832
833    public function setCivicNumber($civic_number)
834    {
835        $civic_number = $this->mDb->escapeString($civic_number);
836        $this->mDb->execSqlUpdate("UPDATE nodes SET civic_number = '{$civic_number}' WHERE node_id = '{$this->getId()}'");
837        $this->refresh();
838    }
839
840    public function getStreetName()
841    {
842        return $this->_row['street_name'];
843    }
844
845    public function setStreetName($street_name)
846    {
847        $street_name = $this->mDb->escapeString($street_name);
848        $this->mDb->execSqlUpdate("UPDATE nodes SET street_name = '{$street_name}' WHERE node_id = '{$this->getId()}'");
849        $this->refresh();
850    }
851
852    public function getCity()
853    {
854        return $this->_row['city'];
855    }
856
857    public function setCity($city)
858    {
859        $city = $this->mDb->escapeString($city);
860        $this->mDb->execSqlUpdate("UPDATE nodes SET city = '{$city}' WHERE node_id = '{$this->getId()}'");
861        $this->refresh();
862    }
863
864    public function getProvince()
865    {
866        return $this->_row['province'];
867    }
868
869    public function setProvince($province)
870    {
871        $province = $this->mDb->escapeString($province);
872        $this->mDb->execSqlUpdate("UPDATE nodes SET province = '{$province}' WHERE node_id = '{$this->getId()}'");
873        $this->refresh();
874    }
875
876    public function getCountry()
877    {
878        return $this->_row['country'];
879    }
880
881    protected function setCountry($country)
882    {
883        $country = $this->mDb->escapeString($country);
884        $this->mDb->execSqlUpdate("UPDATE nodes SET country = '{$country}' WHERE node_id = '{$this->getId()}'");
885        $this->refresh();
886    }
887
888    public function getPostalCode()
889    {
890        return $this->_row['postal_code'];
891    }
892
893    public function setPostalCode($postal_code)
894    {
895        $postal_code = $this->mDb->escapeString($postal_code);
896        $this->mDb->execSqlUpdate("UPDATE nodes SET postal_code = '{$postal_code}' WHERE node_id = '{$this->getId()}'");
897        $this->refresh();
898    }
899
900    function getTelephone()
901    {
902        return $this->_row['public_phone_number'];
903    }
904
905    function setTelephone($phone)
906    {
907        $phone = $this->mDb->escapeString($phone);
908        $this->mDb->execSqlUpdate("UPDATE nodes SET public_phone_number = '{$phone}' WHERE node_id = '{$this->getId()}'");
909        $this->refresh();
910    }
911
912    function getTransitInfo()
913    {
914        return $this->_row['mass_transit_info'];
915    }
916
917    function setTransitInfo($transit_info)
918    {
919        $transit_info = $this->mDb->escapeString($transit_info);
920        $this->mDb->execSqlUpdate("UPDATE nodes SET mass_transit_info = '{$transit_info}' WHERE node_id = '{$this->getId()}'");
921        $this->refresh();
922    }
923
924    function getEmail()
925    {
926        return $this->_row['public_email'];
927    }
928
929    function setEmail($email)
930    {
931        $email = $this->mDb->escapeString($email);
932        $this->mDb->execSqlUpdate("UPDATE nodes SET public_email = '{$email}' WHERE node_id = '{$this->getId()}'");
933        $this->refresh();
934    }
935
936    function getDeploymentStatus()
937    {
938        return $this->_row['node_deployment_status'];
939    }
940
941    function setDeploymentStatus($status)
942    {
943        $status = $this->mDb->escapeString($status);
944        $this->mDb->execSqlUpdate("UPDATE nodes SET node_deployment_status = '{$status}' WHERE node_id = '{$this->getId()}'");
945        $this->refresh();
946    }
947
948    function getAllowsPublicStats()
949    {
950        return (($this->_row['allows_public_stats'] == 't') ? true : false);
951    }
952
953    function setAllowsPublicStats($allowed)
954    {
955        $allowed = $allowed ? 't':'f';
956        $allowed = $this->mDb->escapeString($allowed);
957        $this->mDb->execSqlUpdate("UPDATE nodes SET allows_public_stats = BOOL('$allowed') WHERE node_id = '{$this->getId()}'");
958        $this->refresh();
959
960        //FIXME: Delete the folder if necessary?
961    }
962
963    function hasPublicStats()
964    {
965        return file_exists($this->getPublicStatsDir() . $this->getPublicStatsFile());
966    }
967
968    function getPublicStatsDir()
969    {
970        return WIFIDOG_ABS_FILE_PATH . NODE_PUBLIC_STATS_DIR . $this->getId() . "/";
971    }
972
973    function getPublicStatsFile()
974    {
975        return "index.html";
976    }
977
978    function getLastPaged()
979    {
980        return $this->_row['last_paged'];
981    }
982
983    function setLastPaged($last_paged)
984    {
985        $this->mDb->execSqlUpdate("UPDATE nodes SET last_paged = {$last_paged}::abstime WHERE node_id = '{$this->getId()}'");
986        $this->refresh();
987    }
988
989    function getLastHeartbeatIP()
990    {
991        return $this->_row['last_heartbeat_ip'];
992    }
993
994    function getLastHeartbeatUserAgent()
995    {
996        return $this->_row['last_heartbeat_user_agent'];
997    }
998
999    function getLastHeartbeatWifidogUptime()
1000    {
1001        return $this->_row['last_heartbeat_wifidog_uptime'];
1002    }
1003
1004    function getLastHeartbeatSysUptime()
1005    {
1006        return $this->_row['last_heartbeat_sys_uptime'];
1007    }
1008
1009    function getLastHeartbeatSysLoad()
1010    {
1011        return $this->_row['last_heartbeat_sys_load'];
1012    }
1013
1014    function getLastHeartbeatSysMemfree()
1015    {
1016        return $this->_row['last_heartbeat_sys_memfree'];
1017    }
1018
1019    function getLastHeartbeatTimestamp()
1020    {
1021        return $this->_row['last_heartbeat_timestamp'];
1022    }
1023
1024    function setLastHeartbeatTimestamp($timestamp)
1025    {
1026        $this->mDb->execSqlUpdate("UPDATE nodes SET last_heartbeat_timestamp = '{$timestamp}' WHERE node_id = '{$this->getId()}'");
1027        $this->refresh();
1028    }
1029
1030    /** Is the node a Splash Only node?  Will only return true if the Network configuration allows it.
1031     * @return true or false */
1032    public function isSplashOnly()
1033    {
1034        return $this->getNetwork()->getSplashOnlyNodesAllowed() && $this->isConfiguredSplashOnly();
1035    }
1036
1037    /** Is the node configured as a Splash Only node?  This is NOT the same as isSplashOnly().
1038     * This is the getter for the configuration set in the database for this node.
1039     * For the node to actually be splash only, this AND the network
1040     * gonfiguration must match.
1041     * @return true or false */
1042    public function isConfiguredSplashOnly()
1043    {
1044        return (($this->_row['is_splash_only_node'] == 't') ? true : false);
1045    }
1046
1047    /** Set if this node should be a splash-only (no login) node (if enabled in Network configuration)
1048     * @param $value The new value, true or false
1049     * @return true on success, false on failure */
1050    function setIsConfiguredSplashOnly($value)
1051    {
1052        $retval = true;
1053        if ($value != $this->isConfiguredSplashOnly())
1054        {
1055            $db = AbstractDb::getObject();
1056            $value ? $value = 'TRUE' : $value = 'FALSE';
1057            $retval = $db->execSqlUpdate("UPDATE nodes SET is_splash_only_node = {$value} WHERE node_id = '{$this->getId()}'", false);
1058            $this->refresh();
1059        }
1060        return $retval;
1061    }
1062
1063    /** The url to show instead of the portal.  If empty, the portal is shown
1064     Must be enabled in the Network configuration to have any effect
1065     @return a string */
1066    function getCustomPortalRedirectUrl()
1067    {
1068        return $this->_row['custom_portal_redirect_url'];
1069    }
1070
1071    /** The url to show instead of the portal.  If empty, the portal is shown
1072     Must be enabled in the Network configuration to have any effect
1073     @return true on success, false on failure */
1074    function setCustomPortalRedirectUrl($value)
1075    {
1076        $retval = true;
1077        if ($value != $this->getCustomPortalRedirectUrl())
1078        {
1079            $db = AbstractDb::getObject();
1080            $value = $db->escapeString($value);
1081            $retval = $db->execSqlUpdate("UPDATE nodes SET custom_portal_redirect_url = '{$value}' WHERE node_id = '{$this->getId()}'", false);
1082            $this->refresh();
1083        }
1084        return $retval;
1085    }
1086
1087    /** redirect users to the original requested web page instead of portal
1088     Must be enabled in the Network configuration to have any effect
1089     @return a string */
1090    function getPortalOriginalUrlAllowed()
1091    {
1092        return (($this->_row['allow_original_url_redirect'] == 't') ? true : false);
1093    }
1094
1095    /** redirect users to the original requested web page instead of portal
1096     Must be enabled in the Network configuration to have any effect
1097     @return true on success, false on failure */
1098    function setPortalOriginalUrlAllowed($value)
1099    {
1100        $retval = true;
1101        if ($value != $this->getPortalOriginalUrlAllowed())
1102        {
1103            $db = AbstractDb::getObject();
1104            $value ? $value = 'TRUE' : $value = 'FALSE';
1105            $retval = $db->execSqlUpdate("UPDATE nodes SET allow_original_url_redirect = '{$value}' WHERE node_id = '{$this->getId()}'", false);
1106            $this->refresh();
1107        }
1108        return $retval;
1109    }
1110
1111    /** disable dynamic abuse control for all users of this node
1112     * @return a string */
1113    function getBypassDynamicAbuseControl()
1114    {
1115        return (($this->_row['bypass_dynamic_abuse_control'] == 't') ? true : false);
1116    }
1117
1118    /** disable dynamic abuse control for all users of this node
1119     * @return true on success, false on failure */
1120    function setBypassDynamicAbuseControl($value)
1121    {
1122        $retval = true;
1123        if ($value != $this->getBypassDynamicAbuseControl())
1124        {
1125            $db = AbstractDb::getObject();
1126            $value ? $value = 'TRUE' : $value = 'FALSE';
1127            $retval = $db->execSqlUpdate("UPDATE nodes SET bypass_dynamic_abuse_control = '{$value}' WHERE node_id = '{$this->getId()}'", false);
1128            $this->refresh();
1129        }
1130        return $retval;
1131    }
1132
1133
1134
1135    /**
1136     * Retrieves the admin interface of this object
1137     *
1138     * @return string The HTML fragment for this interface
1139     *
1140     * @access public
1141     *
1142     * @todo Most of this code will be moved to Hotspot class when the
1143     *       abtraction will be completed
1144     */
1145    public function getAdminUI()
1146    {
1147        $permArray=null;
1148        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
1149        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
1150        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1151        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1152        Security::requireAnyPermission($permArray);
1153        require_once('classes/InterfaceElements.php');
1154        require_once('classes/Stakeholder.php');
1155        // Init values
1156        $html = '';
1157
1158        // Get information about the network
1159        $network = $this->getNetwork();
1160
1161        $node_id = $this->getId();
1162
1163        /*
1164         * Check for a warning message
1165         */
1166        if ($this->_warningMessage != "") {
1167            $html .= "<div class='errormsg'>".$this->_warningMessage."</div>\n";
1168        }
1169
1170        /*
1171         * Begin with admin interface
1172         */
1173        $html .= "<fieldset class='admin_container ".get_class($this)."'>\n";
1174        $html .= "<legend>"._("Edit a node")."</legend>\n";
1175        $html .= "<ul class='admin_element_list'>\n";
1176
1177        /*
1178         * Display stats
1179         */
1180        $permArray = null;
1181        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1182        $permArray[]=array(Permission::P('NODE_PERM_ALLOW_GENERATING_PUBLIC_STATS'), $this);
1183        if (Security::hasAnyPermission($permArray)) {
1184            $_title = _("Statistics");
1185            $_data = InterfaceElements::generateInputCheckbox("allows_public_stats","", _("Allow public access to some node statistics."), $this->getAllowsPublicStats(), "allows_public_stats");
1186            $_data .= InterfaceElements::generateInputSubmit("node_" . $this->id . "_get_stats", _("Get access statistics"), "node_get_stats_submit");
1187            $html .= InterfaceElements::generateAdminSectionContainer("node_get_stats", $_title, $_data);
1188        }
1189
1190        /*
1191         * Information about the node
1192         */
1193        $_html_node_information = array();
1194
1195        // Gateway ID
1196        $_title = _("Gateway ID");
1197        $permArray = null;
1198        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1199        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1200        if (Security::hasAnyPermission($permArray)) {
1201            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gw_id", $this->getGatewayId(), "gw_id_input");
1202        } else {
1203            $_data  = htmlspecialchars($this->getGatewayId(), ENT_QUOTES);
1204            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_gw_id", $this->getGatewayId());
1205        }
1206        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("gateway_id", $_title, $_data);
1207
1208        //Node content
1209       
1210        $html .= parent::getContentAdminUI();
1211           
1212        // Name
1213        $permArray = null;
1214        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1215        $permArray[]=array(Permission::P('NODE_PERM_EDIT_NAME'), $this);
1216        if (Security::hasAnyPermission($permArray)) {
1217            $_title = _("Name");
1218            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_name", $this->getName(), "node_name_input");
1219            $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_name", $_title, $_data);
1220        }
1221        else {
1222            $_title = _("Name");
1223            $_data = $this->getName();
1224            $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_name", $_title, $_data);
1225        }
1226
1227        // Creation date
1228        $_title = _("Creation date");
1229        $permArray = null;
1230        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1231        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1232        if (Security::hasAnyPermission($permArray)) {
1233            $_data = DateTimeWD::getSelectDateTimeUI(new DateTimeWD($this->getCreationDate()), "node_" . $node_id . "_creation_date", DateTimeWD::INTERFACE_DATETIME_FIELD, "node_creation_date_input");
1234        } else {
1235            $_data  = htmlspecialchars($this->getCreationDate(), ENT_QUOTES);
1236            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_creation_date", $this->getCreationDate());
1237        }
1238        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_creation_date", $_title, $_data);
1239
1240        // Description
1241        $_title = _("Description");
1242        $name = "node_" . $node_id . "_description";
1243        $_data = "<textarea name='$name' cols=80 rows=5 id='node_description_textarea'>\n".$this->getDescription()."\n</textarea>\n";
1244        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_description", $_title, $_data);
1245
1246        // Civic number
1247        $_title = _("Civic number");
1248        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_civic_number", $this->getCivicNumber(), "node_civic_number_input");
1249        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_civic_number", $_title, $_data);
1250
1251        // Street name
1252        $_title = _("Street name");
1253        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_street_name", $this->getStreetName(), "node_street_name_input");
1254        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_street_name", $_title, $_data);
1255
1256        // City
1257        $_title = _("City");
1258        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_city", $this->getCity(), "node_city_input");
1259        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_city", $_title, $_data);
1260
1261        // Province
1262        $_title = _("Province / State");
1263        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_province", $this->getProvince(), "node_province_input");
1264        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_province", $_title, $_data);
1265
1266        // Postal Code
1267        $_title = _("Postal code");
1268        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_postal_code", $this->getPostalCode(), "node_postal_code_input");
1269        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_postal_code", $_title, $_data);
1270
1271        // Country
1272        $_title = _("Country");
1273        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_country", $this->getCountry(), "node_country_input");
1274        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_country", $_title, $_data);
1275
1276        // Public phone #
1277        $_title = _("Public phone number");
1278        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_phone", $this->getTelephone(), "node_public_phone_input");
1279        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_phone", $_title, $_data);
1280
1281        // Public mail
1282        $_title = _("Public email");
1283        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_email", $this->getEmail(), "node_public_email_input");
1284        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_email", $_title, $_data);
1285
1286        // Homepage URL
1287        $_title = _("Homepage URL");
1288        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_homepage_url", $this->getWebSiteURL(), "node_homepage_url_input");
1289        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_homepage_url", $_title, $_data);
1290
1291        // Mass transit info
1292        $_title = _("Mass transit info");
1293        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_mass_transit_info", $this->getTransitInfo(), "node_mass_transit_info_input");
1294        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_mass_transit_info", $_title, $_data);
1295
1296        // Build section
1297        $html .= InterfaceElements::generateAdminSectionContainer("node_information", _("Information about the node"), implode(null, $_html_node_information));
1298
1299        /*
1300         * Node GIS data
1301         */
1302        $_html_node_gis_data = array();
1303        $gis_point = $this->getGisLocation();
1304
1305        // Latitude
1306        $_title = _("Latitude");
1307        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_latitude", $gis_point->getLatitude(), "node_" . $node_id . "_gis_latitude");
1308        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_latitude", $_title, $_data);
1309
1310        // Latitude
1311        $_title = _("Longitude");
1312        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_longitude", $gis_point->getLongitude(), "node_" . $node_id . "_gis_longitude");
1313        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_longitude", $_title, $_data);
1314
1315        // Call the geocoding service, if Google Maps is enabled then use Google Maps to let the user choose a more precise location
1316        if (defined('GMAPS_HOTSPOTS_MAP_ENABLED') && GMAPS_HOTSPOTS_MAP_ENABLED === true) {
1317            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1318            $_data .= InterfaceElements::generateInputButton("google_maps_geocode", _("Check using Google Maps"), "google_maps_geocode_button", "submit", array("onclick" => "window.open('hotspot_location_map.php?node_id={$this->getId()}', 'hotspot_location', 'toolbar = 0, scrollbars = 1, resizable = 1, location = 0, statusbar = 0, menubar = 0, width = 600, height = 600');"));
1319            $_data .= "<div class='admin_section_hint' id='node_gis_geocode_hint'>". "(" . _("Use a geocoding service, then use Google Maps to pinpoint the exact location.") . ")" ."</div>\n";
1320        } else {
1321            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1322            $_data .= "<div class='admin_section_hint' id='node_gis_geocode_hint'>". "(" . _("Use a geocoding service") . ")" ."</div>\n";
1323        }
1324
1325        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_geocode", "", $_data);
1326
1327        // Map URL
1328        $_title = _("Map URL");
1329        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_map_url", $this->getMapURL(), "node_map_url_input");
1330        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_map_url", $_title, $_data);
1331
1332        // Build section
1333        $html .= InterfaceElements::generateAdminSectionContainer("node_gis_data", _("GIS data"), implode(null, $_html_node_gis_data));
1334
1335        /*
1336         * Node configuration section
1337         */
1338        $_html_node_config = array();
1339
1340        // Deployment status
1341        $_title = _("Node deployment status");
1342        $_data = $this->getSelectDeploymentStatus("node_" . $node_id . "_deployment_status");
1343        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_deployment_status", $_title, $_data);
1344
1345        // Network selection
1346        $_title = _("Node Network");
1347        $_data = Network::getSelectUI("node_" . $node_id . "_network_id", array('preSelectedObject'=>$this->getNetwork()));
1348        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_network", $_title, $_data);
1349
1350        //  is_splash_only_node
1351        if ($network->getSplashOnlyNodesAllowed()) {
1352            $_title = _("Is this node splash-only (no login)?");
1353            $_data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_is_splash_only_node", "", _("Yes"), $this->isConfiguredSplashOnly(), "node_is_splash_only_node_radio");
1354            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_is_splash_only_node", $_title, $_data);
1355        }
1356
1357        // custom_portal_redirect_url
1358        if ($network->getCustomPortalRedirectAllowed()) {
1359            $_title = _("URL to show instead of the portal");
1360            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_custom_portal_redirect_url", $this->getCustomPortalRedirectUrl(), "node_custom_portal_redirect_url_input");
1361            $_data .= _("If this is not empty, the portal will be disabled and this URL will be shown instead");
1362            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_custom_portal_redirect_url", $_title, $_data);
1363        }
1364
1365        //  allow_original_URL_redirect
1366        $title = _("Original URL redirection");
1367        $help = _("Are nodes allowed to redirect users to the web page they originally requested instead of the portal? this will overide the custom portal URL");
1368        $data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_allow_original_URL_redirect", "", _("Yes"), $this->getPortalOriginalUrlAllowed(), "node_allow_original_URL_redirect_radio");
1369        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_allow_original_URL_redirect", $title, $data, $help);
1370
1371        // bypass_dynamic_abuse_control
1372        $title = _("Bypass dynamic abuse control");
1373        $help = _("Do you need to disable abuse control for this node? This will affect all users using this node. This will overide the network configuration.");
1374        $data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_bypass_dynamic_abuse_control", "", _("Disable dynamic abuse control"), $this->getBypassDynamicAbuseControl(), "bypass_dynamic_abuse_control_radio");
1375        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("bypass_dynamic_abuse_control", $title, $data, $help);
1376
1377        // Build section
1378        $html .= InterfaceElements::generateAdminSectionContainer("node_config", _("Node configuration"), implode(null, $_html_node_config));
1379
1380        /*
1381         * Access rights
1382         */
1383        if (User::getCurrentUser()->DEPRECATEDisSuperAdmin()) {
1384            require_once('classes/Stakeholder.php');
1385            $html_access_rights = Stakeholder::getAssignStakeholdersUI($this);
1386            $html .= InterfaceElements::generateAdminSectionContainer("access_rights", _("Access rights"), $html_access_rights);
1387        }
1388       
1389        //Node hierarchy
1390        $html .= parent::getGraphAdminUI($network);
1391
1392        $html .= "</ul>\n";
1393        $html .= "</fieldset>";
1394
1395        return $html;
1396    }
1397
1398    /**
1399     * Process admin interface of this object.
1400     *
1401     * @return void
1402     *
1403     * @access public
1404     */
1405    public function processAdminUI()
1406    {
1407        require_once('classes/Stakeholder.php');
1408        $user = User::getCurrentUser();
1409        // Get information about the network
1410        $network = $this->getNetwork();
1411        //pretty_print_r($_REQUEST);
1412        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
1413        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
1414        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1415        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1416        Security::requireAnyPermission($permArray);
1417        // Check if user is a admin
1418        $_userIsAdmin = User::getCurrentUser()->DEPRECATEDisSuperAdmin();
1419
1420        // Information about the node
1421
1422        $node_id = $this->getId();
1423
1424        // Gateway Id
1425        $permArray = null;
1426        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1427        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1428        if (Security::hasAnyPermission($permArray)) {
1429            $name = "node_" . $node_id . "_gw_id";
1430            $this->setGatewayId($_REQUEST[$name]);
1431        }
1432        // Content processing
1433        parent::processContentAdminUI();
1434
1435        // Name
1436        $permArray = null;
1437        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1438        $permArray[]=array(Permission::P('NODE_PERM_EDIT_NAME'), $this);
1439        if (Security::hasAnyPermission($permArray)) {
1440            $name = "node_".$node_id."_name";
1441            $this->setName($_REQUEST[$name]);
1442        }
1443
1444        // Creation date
1445        $permArray = null;
1446        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1447        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1448        if (Security::hasAnyPermission($permArray)) {
1449            $name = "node_".$node_id."_creation_date";
1450            $this->setCreationDate(DateTimeWD::processSelectDateTimeUI($name, DateTimeWD :: INTERFACE_DATETIME_FIELD)->getIso8601FormattedString());
1451        }
1452
1453        // Homepage URL
1454        $name = "node_".$node_id."_homepage_url";
1455        $this->setWebSiteUrl($_REQUEST[$name]);
1456
1457        // Description
1458        $name = "node_".$node_id."_description";
1459        $this->setDescription($_REQUEST[$name]);
1460
1461        // Map URL
1462        $name = "node_".$node_id."_map_url";
1463        $this->setMapUrl($_REQUEST[$name]);
1464
1465        // Civic number
1466        $name = "node_".$node_id."_civic_number";
1467        $this->setCivicNumber($_REQUEST[$name]);
1468
1469        // Street name
1470        $name = "node_".$node_id."_street_name";
1471        $this->setStreetName($_REQUEST[$name]);
1472
1473        // City
1474        $name = "node_".$node_id."_city";
1475        $this->setCity($_REQUEST[$name]);
1476
1477        // Province
1478        $name = "node_".$node_id."_province";
1479        $this->setProvince($_REQUEST[$name]);
1480
1481        // Postal Code
1482        $name = "node_".$node_id."_postal_code";
1483        $this->setPostalCode($_REQUEST[$name]);
1484
1485        // Country
1486        $name = "node_".$node_id."_country";
1487        $this->setCountry($_REQUEST[$name]);
1488
1489        // Public phone #
1490        $name = "node_".$node_id."_public_phone";
1491        $this->setTelephone($_REQUEST[$name]);
1492
1493        // Public mail
1494        $name = "node_".$node_id."_public_email";
1495        $this->setEmail($_REQUEST[$name]);
1496
1497        // Mass transit info
1498        $name = "node_".$node_id."_mass_transit_info";
1499        $this->setTransitInfo($_REQUEST[$name]);
1500
1501        // GIS data
1502        // Get a geocoder for a given country
1503        if (!empty ($_REQUEST['geocode_only']))
1504        {
1505            if ($geocoder = AbstractGeocoder :: getGeocoder($this->getCountry()) != null)
1506                $geocoder = AbstractGeocoder :: getGeocoder($this->getCountry());         
1507            else
1508                $geocoder = AbstractGeocoder :: getGeocoder('Earth');
1509
1510            if ($geocoder != null)
1511            {
1512                $geocoder->setCivicNumber($this->getCivicNumber());
1513                $geocoder->setStreetName($this->getStreetName());
1514                $geocoder->setCity($this->getCity());
1515                $geocoder->setProvince($this->getProvince());
1516                $geocoder->setPostalCode($this->getPostalCode());
1517                if ($geocoder->validateAddress() == true)
1518                {
1519                    if (($point = $geocoder->getGisLocation()) !== null)
1520                    $this->setGisLocation($point);
1521                    else
1522                    $this->_warningMessage = _("It appears that the Geocoder could not be reached or could not geocode the given address.");
1523                }
1524                else
1525                $this->_warningMessage = _("You must enter a valid address.");
1526            }
1527            else
1528            {
1529                $this->_warningMessage = _("Unable to create geocoder.  Are you sure you set the country?");
1530            }
1531        }
1532        else
1533        {
1534            // Use what has been set by the user.
1535            $gis_lat_name = "node_".$node_id."_gis_latitude";
1536            $gis_long_name = "node_".$node_id."_gis_longitude";
1537            $this->setGisLocation(new GisPoint($_REQUEST[$gis_lat_name], $_REQUEST[$gis_long_name], .0));
1538        }
1539
1540        // Statistics
1541        $name = "node_{$this->id}_get_stats";
1542        if (!empty ($_REQUEST[$name]))
1543        header("Location: stats.php?".urlencode("selected_nodes[]")."=".urlencode($this->getId()));
1544        $permArray = null;
1545        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1546        $permArray[]=array(Permission::P('NODE_PERM_ALLOW_GENERATING_PUBLIC_STATS'), $this);
1547        if (Security::hasAnyPermission($permArray)) {
1548
1549            if (isset($_REQUEST['allows_public_stats'])){
1550                $this->setAllowsPublicStats($_REQUEST['allows_public_stats']=='on');
1551            } else {
1552                $this->setAllowsPublicStats(false);
1553            }
1554        }
1555         
1556        // Node configuration section
1557
1558        $network = $this->getNetwork();
1559
1560        // Deployment status
1561        $name = "node_".$node_id."_deployment_status";
1562        $this->setDeploymentStatus(self :: processSelectDeploymentStatus($name));
1563
1564        // Network selection
1565        $name = "node_".$node_id."_network_id";
1566        $new_network=Network :: processSelectUI($name);
1567        if($new_network!=$this->getNetwork()) {
1568            Security::requirePermission(Permission::P('NETWORK_PERM_ADD_NODE'), $new_network);
1569            $this->setNetwork($new_network);
1570        }
1571
1572        //  is_splash_only_node
1573        if ($network->getSplashOnlyNodesAllowed())
1574        {
1575            $name = "node_".$node_id."_is_splash_only_node";
1576            $this->setIsConfiguredSplashOnly(empty ($_REQUEST[$name]) ? false : true);
1577        }
1578
1579        // custom_portal_redirect_url
1580        if ($network->getCustomPortalRedirectAllowed())
1581        {
1582            $name = "node_".$node_id."_custom_portal_redirect_url";
1583            $this->setCustomPortalRedirectUrl($_REQUEST[$name]);
1584        }
1585
1586        // allow_original_URL_redirect
1587        if ($network->getPortalOriginalUrlAllowed())
1588        {
1589            $name = "node_" . $node_id . "_allow_original_URL_redirect";
1590            $this->setPortalOriginalUrlAllowed(empty ($_REQUEST[$name]) ? false : true);
1591        }
1592
1593        // bypass_dynamic_abuse_control
1594        $name = "node_" . $node_id . "_bypass_dynamic_abuse_control";
1595        $this->setBypassDynamicAbuseControl(empty ($_REQUEST[$name]) ? false : true);
1596
1597
1598        // End Node configuration section
1599       
1600        parent::processGraphAdminUI($errMsg, $network);
1601        if(!empty($errMsg)) {
1602            echo $errMsg;
1603            $errMsg = null;
1604        }
1605
1606        // Access rights
1607        Stakeholder::processAssignStakeholdersUI($this, $errMsg);
1608        if(!empty($errMsg)) {
1609            echo $errMsg;
1610        }
1611    }
1612
1613    // Redirect to this node's portal page
1614    public function getUserUI()
1615    {
1616        header("Location: ".BASE_SSL_PATH."portal/?node_id=".$this->getId());
1617    }
1618
1619    /**
1620     * The list of the 5 most recent users who have logged into this node in the past week,
1621     * excluding those that are currently connected.
1622     *
1623     * @return array An array of User object, or an empty array
1624     *
1625     * @access public
1626     */
1627    public function getRecentUsers()
1628    {
1629        $numUsers = 5;
1630        $db = AbstractDb::getObject();
1631
1632        // Init values
1633        $retval = array();
1634        $users = null;
1635        $anonUsers = 0;
1636        $weekAgoDate = strftime("%Y-%m-%d 00:00", strtotime("-1 week"));
1637
1638        $sql = null;
1639        $sql .= "SELECT user_id, timestamp_in FROM connections \n";
1640        $sql .= "WHERE connections.node_id='{$this->id}' \n";
1641        $sql .= "AND connections.user_id NOT IN (".$this->getOnlineUsersSql().")  \n";
1642        $sql .= "AND connections.timestamp_in>'{$weekAgoDate}' \n";
1643
1644        $sql .= "ORDER BY connections.timestamp_in DESC\n";
1645        $sql .= "LIMIT $numUsers * 4 \n";
1646        $db->execSql($sql, $users, false);
1647
1648        if ($users != null) {
1649            $alreadyPresentArray[] = array(); //Only keep the top $num
1650            $count = 0;
1651            foreach ($users as $user_row) {
1652                if(empty($alreadyPresentArray[$user_row['user_id']])) {
1653                    $retval[] = User::getObject($user_row['user_id']);
1654                    $alreadyPresentArray[$user_row['user_id']]=true;
1655                    $count++;
1656                    if($count>=$numUsers) {
1657                        break;
1658                    }
1659                }
1660            }
1661        }
1662
1663        return $retval;
1664    }
1665
1666    /**
1667     * The list of the 5 users who have logged into this node the most different days during the last 3 months
1668     *
1669     * @return array An array of User object, or an empty array
1670     *
1671     * @access public
1672     */
1673    public function getActiveUsers()
1674    {
1675        $numUsers = 5;
1676        $db = AbstractDb::getObject();
1677
1678        // Init values
1679        $retval = array();
1680        $users = null;
1681        $anonUsers = 0;
1682        $sql = null;
1683        $sql .= "SELECT DISTINCT connections.user_id, count(distinct date_trunc('day', timestamp_in)) as connections FROM connections \n";
1684        $sql .= " WHERE connections.node_id='{$this->id}' \n";
1685        $sql .= " AND timestamp_in > (CURRENT_TIMESTAMP - interval '3 month') \n";
1686        $sql .= " GROUP BY connections.user_id  \n";
1687        $sql .= "ORDER BY connections desc \n";
1688        $sql .= " LIMIT $numUsers\n";
1689        $db->execSql($sql, $users, false);
1690
1691        if ($users != null) {
1692            foreach ($users as $user_row) {
1693                $retval[] = User::getObject($user_row['user_id']);
1694            }
1695        }
1696
1697        return $retval;
1698    }
1699
1700    private function getOnlineUsersSql() {
1701        return "SELECT users.user_id FROM users,connections JOIN tokens USING (token_id) WHERE tokens.token_status='".TOKEN_INUSE."' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}'";
1702    }
1703    /**
1704     * The list of users online at this node
1705     *
1706     * @return array An array of User object, or an empty array
1707     *
1708     * @access public
1709     */
1710    public function getOnlineUsers()
1711    {
1712         
1713        $db = AbstractDb::getObject();
1714
1715        // Init values
1716        $retval = array();
1717        $users = null;
1718        $anonUsers = 0;
1719        $db->execSql($this->getOnlineUsersSql(), $users, false);
1720        if ($users != null) {
1721            foreach ($users as $user_row) {
1722                $retval[] = User::getObject($user_row['user_id']);
1723            }
1724        }
1725
1726        return $retval;
1727    }
1728
1729    /**
1730     * Find out how many users are online this specific Node
1731     * Counts every user account connected (once for every account), except the splash-only user + every mac adresses connecting as the splash-only user
1732     * @return int Number of online users
1733     *
1734     * @access public
1735     */
1736    public function getNumOnlineUsers()
1737    {
1738        $db = AbstractDb::getObject();
1739        // Init values
1740        $retval = array ();
1741        $row = null;
1742        $splashOnlyUserId = $this->getNetwork()->getSplashOnlyUser()->getId();
1743        $sql = "SELECT ((SELECT COUNT(DISTINCT users.user_id) as count FROM users,connections JOIN tokens USING (token_id) WHERE tokens.token_status='".TOKEN_INUSE."' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}' AND users.user_id!='{$splashOnlyUserId}') + (SELECT COUNT(DISTINCT connections.user_mac) as count FROM users,connections JOIN tokens USING (token_id) WHERE tokens.token_status='".TOKEN_INUSE."' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}' AND users.user_id='{$splashOnlyUserId}')) AS count";
1744        $db->execSqlUniqueRes($sql, $row, false);
1745
1746        return $row['count'];
1747    }
1748
1749
1750    /** The list of all Technical officers of this node.
1751     * Technical officers are displayed highlited and in the online user's list,
1752     * and are contacted when the Node goes down.
1753     * @return An array of User object, or en empty array */
1754    function DEPRECATEDgetTechnicalOfficers()
1755    {
1756        $db = AbstractDb::getObject();
1757        $retval = array ();
1758        $officers = null;
1759        $db->execSql("SELECT user_id FROM node_stakeholders WHERE role_id = 'NODE_TECH_OFFICER' AND object_id='{$this->id}'", $officers, false);
1760        if ($officers != null)
1761        {
1762            foreach ($officers as $officer_row)
1763            {
1764                $retval[] = User :: getObject($officer_row['user_id']);
1765            }
1766        }
1767        return $retval;
1768    }
1769
1770    /** Reloads the object from the database.  Should normally be called after a set operation */
1771    protected function refresh()
1772    {
1773        $this->__construct($this->id);
1774    }
1775    /** Menu hook function */
1776    static public function hookMenu() {
1777        $items = array();
1778        if(Security::getObjectsWithPermission(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG')))
1779        {
1780            $items[] = array('path' => 'node/node_edit',
1781            'title' => _("Edit nodes"),
1782            'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=list")
1783            );
1784        }
1785        else if($nodes = Security::getObjectsWithPermission(Permission::P('NODE_PERM_EDIT_CONFIG'))) {
1786             
1787            foreach ($nodes as $nodeId => $node) {
1788                $items[] = array('path' => 'node/node_'.$nodeId.'edit',
1789                'title' => sprintf(_("Edit %s"), $node->getName()),
1790                'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=edit&object_id=$nodeId")
1791                );
1792            }
1793        }
1794        if(Security::hasPermission(Permission::P('NETWORK_PERM_ADD_NODE'))){
1795            $items[] = array('path' => 'node/node_add_new',
1796                'title' => sprintf(_("Add a new node")),
1797                'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=new_ui")
1798            );
1799        }
1800        $items[] = array('path' => 'node',
1801        'title' => _('Node administration'),
1802        'type' => MENU_ITEM_GROUPING);
1803        return $items;
1804    }
1805    /**
1806     * Assigns values about node to be processed by the Smarty engine.
1807     *
1808     * @param object $smarty Smarty object
1809     * @param object $node    Node object, if unset, the current node will be used
1810     *
1811     * @return void
1812     */
1813    public static function assignSmartyValues($smarty, $node = null)
1814    {
1815        if (!$node) {
1816            $node = self::getCurrentNode();
1817        }
1818
1819        // Set node details
1820        $smarty->assign('nodeId', $node ? $node->getId() : '');
1821        $smarty->assign('nodeName', $node ? $node->getName() : '');
1822        $smarty->assign('nodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1823        $smarty->assign('nodeNumOnlineUsers', $node ? $node->getNumOnlineUsers() : '');
1824        $smarty->assign('nodeWebSiteURL', $node ? $node->getWebSiteURL() : '');
1825        $node = self::getCurrentRealNode();
1826        // Set node details
1827        $smarty->assign('realNodeId', $node ? $node->getId() : '');
1828        $smarty->assign('realNodeName', $node ? $node->getName() : '');
1829        $smarty->assign('realNodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1830    }
1831   
1832    /**
1833     * Get the type of graph element (read-only for now)
1834     *
1835     * @return string
1836     */
1837    protected function getType() {
1838        return 'Node';
1839    }
1840 
1841    /**
1842     * Return whether this element is a root or has parent (Network is root)
1843     * @return boolean
1844     */
1845    public function isRoot(){
1846        return false;
1847    }
1848   
1849                /**
1850     * Return whether this element is a leaf or has children (Node is leaf)
1851     * @return boolean
1852     */
1853    public function isLeaf() {
1854        return true;
1855    }
1856   
1857}
1858
1859/*
1860 * Local variables:
1861 * tab-width: 4
1862 * c-basic-offset: 4
1863 * c-hanging-comment-ender-p: nil
1864 * End:
1865 */
Note: See TracBrowser for help on using the browser.