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

Revision 1440, 70.1 KB (checked in by gbastien, 3 years ago)

* Fixed #691, content for login page, introduced in [1435], also with content everywhere
* Removed some commented code to clean up a bit

  • 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
1112
1113    /**
1114     * Retrieves the admin interface of this object
1115     *
1116     * @return string The HTML fragment for this interface
1117     *
1118     * @access public
1119     *
1120     * @todo Most of this code will be moved to Hotspot class when the
1121     *       abtraction will be completed
1122     */
1123    public function getAdminUI()
1124    {
1125        $permArray=null;
1126        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
1127        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
1128        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1129        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1130        Security::requireAnyPermission($permArray);
1131        require_once('classes/InterfaceElements.php');
1132        require_once('classes/Stakeholder.php');
1133        // Init values
1134        $html = '';
1135
1136        // Get information about the network
1137        $network = $this->getNetwork();
1138
1139        $node_id = $this->getId();
1140
1141        /*
1142         * Check for a warning message
1143         */
1144        if ($this->_warningMessage != "") {
1145            $html .= "<div class='errormsg'>".$this->_warningMessage."</div>\n";
1146        }
1147
1148        /*
1149         * Begin with admin interface
1150         */
1151        $html .= "<fieldset class='admin_container ".get_class($this)."'>\n";
1152        $html .= "<legend>"._("Edit a node")."</legend>\n";
1153        $html .= "<ul class='admin_element_list'>\n";
1154
1155        /*
1156         * Display stats
1157         */
1158        $permArray = null;
1159        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1160        $permArray[]=array(Permission::P('NODE_PERM_ALLOW_GENERATING_PUBLIC_STATS'), $this);
1161        if (Security::hasAnyPermission($permArray)) {
1162            $_title = _("Statistics");
1163            $_data = InterfaceElements::generateInputCheckbox("allows_public_stats","", _("Allow public access to some node statistics."), $this->getAllowsPublicStats(), "allows_public_stats");
1164            $_data .= InterfaceElements::generateInputSubmit("node_" . $this->id . "_get_stats", _("Get access statistics"), "node_get_stats_submit");
1165            $html .= InterfaceElements::generateAdminSectionContainer("node_get_stats", $_title, $_data);
1166        }
1167
1168        /*
1169         * Information about the node
1170         */
1171        $_html_node_information = array();
1172
1173        // Gateway ID
1174        $_title = _("Gateway ID");
1175        $permArray = null;
1176        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1177        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1178        if (Security::hasAnyPermission($permArray)) {
1179            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gw_id", $this->getGatewayId(), "gw_id_input");
1180        } else {
1181            $_data  = htmlspecialchars($this->getGatewayId(), ENT_QUOTES);
1182            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_gw_id", $this->getGatewayId());
1183        }
1184        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("gateway_id", $_title, $_data);
1185
1186        //Node content
1187       
1188        $html .= parent::getContentAdminUI();
1189           
1190        // Name
1191        $permArray = null;
1192        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1193        $permArray[]=array(Permission::P('NODE_PERM_EDIT_NAME'), $this);
1194        if (Security::hasAnyPermission($permArray)) {
1195            $_title = _("Name");
1196            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_name", $this->getName(), "node_name_input");
1197            $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_name", $_title, $_data);
1198        }
1199        else {
1200            $_title = _("Name");
1201            $_data = $this->getName();
1202            $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_name", $_title, $_data);
1203        }
1204
1205        // Creation date
1206        $_title = _("Creation date");
1207        $permArray = null;
1208        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1209        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1210        if (Security::hasAnyPermission($permArray)) {
1211            $_data = DateTimeWD::getSelectDateTimeUI(new DateTimeWD($this->getCreationDate()), "node_" . $node_id . "_creation_date", DateTimeWD::INTERFACE_DATETIME_FIELD, "node_creation_date_input");
1212        } else {
1213            $_data  = htmlspecialchars($this->getCreationDate(), ENT_QUOTES);
1214            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_creation_date", $this->getCreationDate());
1215        }
1216        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_creation_date", $_title, $_data);
1217
1218        // Description
1219        $_title = _("Description");
1220        $name = "node_" . $node_id . "_description";
1221        $_data = "<textarea name='$name' cols=80 rows=5 id='node_description_textarea'>\n".$this->getDescription()."\n</textarea>\n";
1222        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_description", $_title, $_data);
1223
1224        // Civic number
1225        $_title = _("Civic number");
1226        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_civic_number", $this->getCivicNumber(), "node_civic_number_input");
1227        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_civic_number", $_title, $_data);
1228
1229        // Street name
1230        $_title = _("Street name");
1231        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_street_name", $this->getStreetName(), "node_street_name_input");
1232        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_street_name", $_title, $_data);
1233
1234        // City
1235        $_title = _("City");
1236        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_city", $this->getCity(), "node_city_input");
1237        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_city", $_title, $_data);
1238
1239        // Province
1240        $_title = _("Province / State");
1241        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_province", $this->getProvince(), "node_province_input");
1242        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_province", $_title, $_data);
1243
1244        // Postal Code
1245        $_title = _("Postal code");
1246        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_postal_code", $this->getPostalCode(), "node_postal_code_input");
1247        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_postal_code", $_title, $_data);
1248
1249        // Country
1250        $_title = _("Country");
1251        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_country", $this->getCountry(), "node_country_input");
1252        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_country", $_title, $_data);
1253
1254        // Public phone #
1255        $_title = _("Public phone number");
1256        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_phone", $this->getTelephone(), "node_public_phone_input");
1257        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_phone", $_title, $_data);
1258
1259        // Public mail
1260        $_title = _("Public email");
1261        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_email", $this->getEmail(), "node_public_email_input");
1262        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_email", $_title, $_data);
1263
1264        // Homepage URL
1265        $_title = _("Homepage URL");
1266        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_homepage_url", $this->getWebSiteURL(), "node_homepage_url_input");
1267        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_homepage_url", $_title, $_data);
1268
1269        // Mass transit info
1270        $_title = _("Mass transit info");
1271        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_mass_transit_info", $this->getTransitInfo(), "node_mass_transit_info_input");
1272        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_mass_transit_info", $_title, $_data);
1273
1274        // Build section
1275        $html .= InterfaceElements::generateAdminSectionContainer("node_information", _("Information about the node"), implode(null, $_html_node_information));
1276
1277        /*
1278         * Node GIS data
1279         */
1280        $_html_node_gis_data = array();
1281        $gis_point = $this->getGisLocation();
1282
1283        // Latitude
1284        $_title = _("Latitude");
1285        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_latitude", $gis_point->getLatitude(), "node_" . $node_id . "_gis_latitude");
1286        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_latitude", $_title, $_data);
1287
1288        // Latitude
1289        $_title = _("Longitude");
1290        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_longitude", $gis_point->getLongitude(), "node_" . $node_id . "_gis_longitude");
1291        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_longitude", $_title, $_data);
1292
1293        // Call the geocoding service, if Google Maps is enabled then use Google Maps to let the user choose a more precise location
1294        if (defined('GMAPS_HOTSPOTS_MAP_ENABLED') && GMAPS_HOTSPOTS_MAP_ENABLED === true) {
1295            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1296            $_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');"));
1297            $_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";
1298        } else {
1299            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1300            $_data .= "<div class='admin_section_hint' id='node_gis_geocode_hint'>". "(" . _("Use a geocoding service") . ")" ."</div>\n";
1301        }
1302
1303        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_geocode", "", $_data);
1304
1305        // Map URL
1306        $_title = _("Map URL");
1307        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_map_url", $this->getMapURL(), "node_map_url_input");
1308        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_map_url", $_title, $_data);
1309
1310        // Build section
1311        $html .= InterfaceElements::generateAdminSectionContainer("node_gis_data", _("GIS data"), implode(null, $_html_node_gis_data));
1312
1313        /*
1314         * Node configuration section
1315         */
1316        $_html_node_config = array();
1317
1318        // Deployment status
1319        $_title = _("Node deployment status");
1320        $_data = $this->getSelectDeploymentStatus("node_" . $node_id . "_deployment_status");
1321        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_deployment_status", $_title, $_data);
1322
1323        // Network selection
1324        $_title = _("Node Network");
1325        $_data = Network::getSelectUI("node_" . $node_id . "_network_id", array('preSelectedObject'=>$this->getNetwork()));
1326        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_network", $_title, $_data);
1327
1328        //  is_splash_only_node
1329        if ($network->getSplashOnlyNodesAllowed()) {
1330            $_title = _("Is this node splash-only (no login)?");
1331            $_data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_is_splash_only_node", "", _("Yes"), $this->isConfiguredSplashOnly(), "node_is_splash_only_node_radio");
1332            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_is_splash_only_node", $_title, $_data);
1333        }
1334
1335        // custom_portal_redirect_url
1336        if ($network->getCustomPortalRedirectAllowed()) {
1337            $_title = _("URL to show instead of the portal");
1338            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_custom_portal_redirect_url", $this->getCustomPortalRedirectUrl(), "node_custom_portal_redirect_url_input");
1339            $_data .= _("If this is not empty, the portal will be disabled and this URL will be shown instead");
1340            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_custom_portal_redirect_url", $_title, $_data);
1341        }
1342
1343        //  allow_original_URL_redirect
1344        $title = _("Original URL redirection");
1345        $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");
1346        $data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_allow_original_URL_redirect", "", _("Yes"), $this->getPortalOriginalUrlAllowed(), "node_allow_original_URL_redirect_radio");
1347        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_allow_original_URL_redirect", $title, $data, $help);
1348
1349        // Build section
1350        $html .= InterfaceElements::generateAdminSectionContainer("node_config", _("Node configuration"), implode(null, $_html_node_config));
1351
1352        /*
1353         * Access rights
1354         */
1355        if (User::getCurrentUser()->DEPRECATEDisSuperAdmin()) {
1356            require_once('classes/Stakeholder.php');
1357            $html_access_rights = Stakeholder::getAssignStakeholdersUI($this);
1358            $html .= InterfaceElements::generateAdminSectionContainer("access_rights", _("Access rights"), $html_access_rights);
1359        }
1360       
1361        //Node hierarchy
1362        $html .= parent::getGraphAdminUI($network);
1363
1364        $html .= "</ul>\n";
1365        $html .= "</fieldset>";
1366
1367        return $html;
1368    }
1369
1370    /**
1371     * Process admin interface of this object.
1372     *
1373     * @return void
1374     *
1375     * @access public
1376     */
1377    public function processAdminUI()
1378    {
1379        require_once('classes/Stakeholder.php');
1380        $user = User::getCurrentUser();
1381        // Get information about the network
1382        $network = $this->getNetwork();
1383        //pretty_print_r($_REQUEST);
1384        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
1385        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
1386        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1387        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1388        Security::requireAnyPermission($permArray);
1389        // Check if user is a admin
1390        $_userIsAdmin = User::getCurrentUser()->DEPRECATEDisSuperAdmin();
1391
1392        // Information about the node
1393
1394        $node_id = $this->getId();
1395
1396        // Gateway Id
1397        $permArray = null;
1398        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1399        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1400        if (Security::hasAnyPermission($permArray)) {
1401            $name = "node_" . $node_id . "_gw_id";
1402            $this->setGatewayId($_REQUEST[$name]);
1403        }
1404        // Content processing
1405        parent::processContentAdminUI();
1406
1407        // Name
1408        $permArray = null;
1409        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1410        $permArray[]=array(Permission::P('NODE_PERM_EDIT_NAME'), $this);
1411        if (Security::hasAnyPermission($permArray)) {
1412            $name = "node_".$node_id."_name";
1413            $this->setName($_REQUEST[$name]);
1414        }
1415
1416        // Creation date
1417        $permArray = null;
1418        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1419        $permArray[]=array(Permission::P('NODE_PERM_EDIT_DEPLOYMENT_DATE'), $this);
1420        if (Security::hasAnyPermission($permArray)) {
1421            $name = "node_".$node_id."_creation_date";
1422            $this->setCreationDate(DateTimeWD::processSelectDateTimeUI($name, DateTimeWD :: INTERFACE_DATETIME_FIELD)->getIso8601FormattedString());
1423        }
1424
1425        // Homepage URL
1426        $name = "node_".$node_id."_homepage_url";
1427        $this->setWebSiteUrl($_REQUEST[$name]);
1428
1429        // Description
1430        $name = "node_".$node_id."_description";
1431        $this->setDescription($_REQUEST[$name]);
1432
1433        // Map URL
1434        $name = "node_".$node_id."_map_url";
1435        $this->setMapUrl($_REQUEST[$name]);
1436
1437        // Civic number
1438        $name = "node_".$node_id."_civic_number";
1439        $this->setCivicNumber($_REQUEST[$name]);
1440
1441        // Street name
1442        $name = "node_".$node_id."_street_name";
1443        $this->setStreetName($_REQUEST[$name]);
1444
1445        // City
1446        $name = "node_".$node_id."_city";
1447        $this->setCity($_REQUEST[$name]);
1448
1449        // Province
1450        $name = "node_".$node_id."_province";
1451        $this->setProvince($_REQUEST[$name]);
1452
1453        // Postal Code
1454        $name = "node_".$node_id."_postal_code";
1455        $this->setPostalCode($_REQUEST[$name]);
1456
1457        // Country
1458        $name = "node_".$node_id."_country";
1459        $this->setCountry($_REQUEST[$name]);
1460
1461        // Public phone #
1462        $name = "node_".$node_id."_public_phone";
1463        $this->setTelephone($_REQUEST[$name]);
1464
1465        // Public mail
1466        $name = "node_".$node_id."_public_email";
1467        $this->setEmail($_REQUEST[$name]);
1468
1469        // Mass transit info
1470        $name = "node_".$node_id."_mass_transit_info";
1471        $this->setTransitInfo($_REQUEST[$name]);
1472
1473        // GIS data
1474        // Get a geocoder for a given country
1475        if (!empty ($_REQUEST['geocode_only']))
1476        {
1477            if ($geocoder = AbstractGeocoder :: getGeocoder($this->getCountry()) != null)
1478                $geocoder = AbstractGeocoder :: getGeocoder($this->getCountry());         
1479            else
1480                $geocoder = AbstractGeocoder :: getGeocoder('Earth');
1481
1482            if ($geocoder != null)
1483            {
1484                $geocoder->setCivicNumber($this->getCivicNumber());
1485                $geocoder->setStreetName($this->getStreetName());
1486                $geocoder->setCity($this->getCity());
1487                $geocoder->setProvince($this->getProvince());
1488                $geocoder->setPostalCode($this->getPostalCode());
1489                if ($geocoder->validateAddress() == true)
1490                {
1491                    if (($point = $geocoder->getGisLocation()) !== null)
1492                    $this->setGisLocation($point);
1493                    else
1494                    $this->_warningMessage = _("It appears that the Geocoder could not be reached or could not geocode the given address.");
1495                }
1496                else
1497                $this->_warningMessage = _("You must enter a valid address.");
1498            }
1499            else
1500            {
1501                $this->_warningMessage = _("Unable to create geocoder.  Are you sure you set the country?");
1502            }
1503        }
1504        else
1505        {
1506            // Use what has been set by the user.
1507            $gis_lat_name = "node_".$node_id."_gis_latitude";
1508            $gis_long_name = "node_".$node_id."_gis_longitude";
1509            $this->setGisLocation(new GisPoint($_REQUEST[$gis_lat_name], $_REQUEST[$gis_long_name], .0));
1510        }
1511
1512        // Statistics
1513        $name = "node_{$this->id}_get_stats";
1514        if (!empty ($_REQUEST[$name]))
1515        header("Location: stats.php?".urlencode("selected_nodes[]")."=".urlencode($this->getId()));
1516        $permArray = null;
1517        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $network);
1518        $permArray[]=array(Permission::P('NODE_PERM_ALLOW_GENERATING_PUBLIC_STATS'), $this);
1519        if (Security::hasAnyPermission($permArray)) {
1520
1521            if (isset($_REQUEST['allows_public_stats'])){
1522                $this->setAllowsPublicStats($_REQUEST['allows_public_stats']=='on');
1523            } else {
1524                $this->setAllowsPublicStats(false);
1525            }
1526        }
1527         
1528        // Node configuration section
1529
1530        $network = $this->getNetwork();
1531
1532        // Deployment status
1533        $name = "node_".$node_id."_deployment_status";
1534        $this->setDeploymentStatus(self :: processSelectDeploymentStatus($name));
1535
1536        // Network selection
1537        $name = "node_".$node_id."_network_id";
1538        $new_network=Network :: processSelectUI($name);
1539        if($new_network!=$this->getNetwork()) {
1540            Security::requirePermission(Permission::P('NETWORK_PERM_ADD_NODE'), $new_network);
1541            $this->setNetwork($new_network);
1542        }
1543
1544        //  is_splash_only_node
1545        if ($network->getSplashOnlyNodesAllowed())
1546        {
1547            $name = "node_".$node_id."_is_splash_only_node";
1548            $this->setIsConfiguredSplashOnly(empty ($_REQUEST[$name]) ? false : true);
1549        }
1550
1551        // custom_portal_redirect_url
1552        if ($network->getCustomPortalRedirectAllowed())
1553        {
1554            $name = "node_".$node_id."_custom_portal_redirect_url";
1555            $this->setCustomPortalRedirectUrl($_REQUEST[$name]);
1556        }
1557
1558        // allow_original_URL_redirect
1559        if ($network->getPortalOriginalUrlAllowed())
1560        {
1561            $name = "node_" . $node_id . "_allow_original_URL_redirect";
1562            $this->setPortalOriginalUrlAllowed(empty ($_REQUEST[$name]) ? false : true);
1563        }
1564
1565        // End Node configuration section
1566       
1567        parent::processGraphAdminUI($errMsg, $network);
1568        if(!empty($errMsg)) {
1569            echo $errMsg;
1570            $errMsg = null;
1571        }
1572
1573        // Access rights
1574        Stakeholder::processAssignStakeholdersUI($this, $errMsg);
1575        if(!empty($errMsg)) {
1576            echo $errMsg;
1577        }
1578    }
1579
1580    // Redirect to this node's portal page
1581    public function getUserUI()
1582    {
1583        header("Location: ".BASE_SSL_PATH."portal/?node_id=".$this->getId());
1584    }
1585
1586    /**
1587     * The list of the 5 most recent users who have logged into this node in the past week,
1588     * excluding those that are currently connected.
1589     *
1590     * @return array An array of User object, or an empty array
1591     *
1592     * @access public
1593     */
1594    public function getRecentUsers()
1595    {
1596        $numUsers = 5;
1597        $db = AbstractDb::getObject();
1598
1599        // Init values
1600        $retval = array();
1601        $users = null;
1602        $anonUsers = 0;
1603        $weekAgoDate = strftime("%Y-%m-%d 00:00", strtotime("-1 week"));
1604
1605        $sql = null;
1606        $sql .= "SELECT user_id, timestamp_in FROM connections \n";
1607        $sql .= "WHERE connections.node_id='{$this->id}' \n";
1608        $sql .= "AND connections.user_id NOT IN (".$this->getOnlineUsersSql().")  \n";
1609        $sql .= "AND connections.timestamp_in>'{$weekAgoDate}' \n";
1610
1611        $sql .= "ORDER BY connections.timestamp_in DESC\n";
1612        $sql .= "LIMIT $numUsers * 4 \n";
1613        $db->execSql($sql, $users, false);
1614
1615        if ($users != null) {
1616            $alreadyPresentArray[] = array(); //Only keep the top $num
1617            $count = 0;
1618            foreach ($users as $user_row) {
1619                if(empty($alreadyPresentArray[$user_row['user_id']])) {
1620                    $retval[] = User::getObject($user_row['user_id']);
1621                    $alreadyPresentArray[$user_row['user_id']]=true;
1622                    $count++;
1623                    if($count>=$numUsers) {
1624                        break;
1625                    }
1626                }
1627            }
1628        }
1629
1630        return $retval;
1631    }
1632
1633    /**
1634     * The list of the 5 users who have logged into this node the most different days during the last 3 months
1635     *
1636     * @return array An array of User object, or an empty array
1637     *
1638     * @access public
1639     */
1640    public function getActiveUsers()
1641    {
1642        $numUsers = 5;
1643        $db = AbstractDb::getObject();
1644
1645        // Init values
1646        $retval = array();
1647        $users = null;
1648        $anonUsers = 0;
1649        $sql = null;
1650        $sql .= "SELECT DISTINCT connections.user_id, count(distinct date_trunc('day', timestamp_in)) as connections FROM connections \n";
1651        $sql .= " WHERE connections.node_id='{$this->id}' \n";
1652        $sql .= " AND timestamp_in > (CURRENT_TIMESTAMP - interval '3 month') \n";
1653        $sql .= " GROUP BY connections.user_id  \n";
1654        $sql .= "ORDER BY connections desc \n";
1655        $sql .= " LIMIT $numUsers\n";
1656        $db->execSql($sql, $users, false);
1657
1658        if ($users != null) {
1659            foreach ($users as $user_row) {
1660                $retval[] = User::getObject($user_row['user_id']);
1661            }
1662        }
1663
1664        return $retval;
1665    }
1666
1667    private function getOnlineUsersSql() {
1668        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}'";
1669    }
1670    /**
1671     * The list of users online at this node
1672     *
1673     * @return array An array of User object, or an empty array
1674     *
1675     * @access public
1676     */
1677    public function getOnlineUsers()
1678    {
1679         
1680        $db = AbstractDb::getObject();
1681
1682        // Init values
1683        $retval = array();
1684        $users = null;
1685        $anonUsers = 0;
1686        $db->execSql($this->getOnlineUsersSql(), $users, false);
1687        if ($users != null) {
1688            foreach ($users as $user_row) {
1689                $retval[] = User::getObject($user_row['user_id']);
1690            }
1691        }
1692
1693        return $retval;
1694    }
1695
1696    /**
1697     * Find out how many users are online this specific Node
1698     * Counts every user account connected (once for every account), except the splash-only user + every mac adresses connecting as the splash-only user
1699     * @return int Number of online users
1700     *
1701     * @access public
1702     */
1703    public function getNumOnlineUsers()
1704    {
1705        $db = AbstractDb::getObject();
1706        // Init values
1707        $retval = array ();
1708        $row = null;
1709        $splashOnlyUserId = $this->getNetwork()->getSplashOnlyUser()->getId();
1710        $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";
1711        $db->execSqlUniqueRes($sql, $row, false);
1712
1713        return $row['count'];
1714    }
1715
1716
1717    /** The list of all Technical officers of this node.
1718     * Technical officers are displayed highlited and in the online user's list,
1719     * and are contacted when the Node goes down.
1720     * @return An array of User object, or en empty array */
1721    function DEPRECATEDgetTechnicalOfficers()
1722    {
1723        $db = AbstractDb::getObject();
1724        $retval = array ();
1725        $officers = null;
1726        $db->execSql("SELECT user_id FROM node_stakeholders WHERE role_id = 'NODE_TECH_OFFICER' AND object_id='{$this->id}'", $officers, false);
1727        if ($officers != null)
1728        {
1729            foreach ($officers as $officer_row)
1730            {
1731                $retval[] = User :: getObject($officer_row['user_id']);
1732            }
1733        }
1734        return $retval;
1735    }
1736
1737    /** Reloads the object from the database.  Should normally be called after a set operation */
1738    protected function refresh()
1739    {
1740        $this->__construct($this->id);
1741    }
1742    /** Menu hook function */
1743    static public function hookMenu() {
1744        $items = array();
1745        if(Security::getObjectsWithPermission(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG')))
1746        {
1747            $items[] = array('path' => 'node/node_edit',
1748            'title' => _("Edit nodes"),
1749            'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=list")
1750            );
1751        }
1752        else if($nodes = Security::getObjectsWithPermission(Permission::P('NODE_PERM_EDIT_CONFIG'))) {
1753             
1754            foreach ($nodes as $nodeId => $node) {
1755                $items[] = array('path' => 'node/node_'.$nodeId.'edit',
1756                'title' => sprintf(_("Edit %s"), $node->getName()),
1757                'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=edit&object_id=$nodeId")
1758                );
1759            }
1760        }
1761        if(Security::hasPermission(Permission::P('NETWORK_PERM_ADD_NODE'))){
1762            $items[] = array('path' => 'node/node_add_new',
1763                'title' => sprintf(_("Add a new node")),
1764                'url' => BASE_URL_PATH.htmlspecialchars("admin/generic_object_admin.php?object_class=Node&action=new_ui")
1765            );
1766        }
1767        $items[] = array('path' => 'node',
1768        'title' => _('Node administration'),
1769        'type' => MENU_ITEM_GROUPING);
1770        return $items;
1771    }
1772    /**
1773     * Assigns values about node to be processed by the Smarty engine.
1774     *
1775     * @param object $smarty Smarty object
1776     * @param object $node    Node object, if unset, the current node will be used
1777     *
1778     * @return void
1779     */
1780    public static function assignSmartyValues($smarty, $node = null)
1781    {
1782        if (!$node) {
1783            $node = self::getCurrentNode();
1784        }
1785
1786        // Set node details
1787        $smarty->assign('nodeId', $node ? $node->getId() : '');
1788        $smarty->assign('nodeName', $node ? $node->getName() : '');
1789        $smarty->assign('nodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1790        $smarty->assign('nodeNumOnlineUsers', $node ? $node->getNumOnlineUsers() : '');
1791        $smarty->assign('nodeWebSiteURL', $node ? $node->getWebSiteURL() : '');
1792        $node = self::getCurrentRealNode();
1793        // Set node details
1794        $smarty->assign('realNodeId', $node ? $node->getId() : '');
1795        $smarty->assign('realNodeName', $node ? $node->getName() : '');
1796        $smarty->assign('realNodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1797    }
1798   
1799    /**
1800     * Get the type of graph element (read-only for now)
1801     *
1802     * @return string
1803     */
1804    protected function getType() {
1805        return 'Node';
1806    }
1807 
1808    /**
1809     * Return whether this element is a root or has parent (Network is root)
1810     * @return boolean
1811     */
1812    public function isRoot(){
1813        return false;
1814    }
1815   
1816                /**
1817     * Return whether this element is a leaf or has children (Node is leaf)
1818     * @return boolean
1819     */
1820    public function isLeaf() {
1821        return true;
1822    }
1823   
1824}
1825
1826/*
1827 * Local variables:
1828 * tab-width: 4
1829 * c-basic-offset: 4
1830 * c-hanging-comment-ender-p: nil
1831 * End:
1832 */
Note: See TracBrowser for help on using the browser.