root/trunk/wifidog-auth/wifidog/classes/Node.php @ 1384

Revision 1384, 66.8 KB (checked in by networkfusion, 5 years ago)

* Support for redirecting to the users original URL instead of portal

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