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

Revision 1249, 55.1 KB (checked in by benoitg, 6 years ago)

-This is a behemoth "the road to 1.0" commit. I've been working on this for 6 months,
and it's reached the point where others can help. Those are very far reaching changes, please
notify me if anything isn't working right (and im sure I can't have caught everything).

Mostly complete. Missing parts are Content stakeholders, system roles and "su" functionnality.
I need help replacing all the DEPRECATED* methods. Please read the wiki page above for instructions.

  • generic_object_admin.php: More work towards making it generic once again.
  • GenericDataObject?: New class. Eventually, most classes should extend this, instead of directly implementing GenericObject?
  • Menu.php: Finally a uniform Menuing system to replace the mismatch of links that made wifidog impossible to navigate. It's not very sophisticated yet, but it IS permission aware Loosely inspired from Drupal's menuing system. HTML is slightly modified "Son of suckerfish", so will be easy to style (althouh I haven't had time yet). Actual menus are added in the hook_menu methods of each class.
  • VirtualHost.php: Finally properly split off Virtual Hosts, and make Server a singleton.
  • install.php: Do the bare minimum changes so it's still possible to setup a wifidog auth server. However, install.php still needs 1- A good overhaull, 2- A way to install sample databases instead of the minimal one. -Other changes
  • Unbreak signup link for non-javascript enabled devices
  • AbstractDb?: Improve debuging features
  • *:getObject(): Hopefully improve performance of class caching by making sure that we do not manipulate different objects. Otherwise copies would be generated as soon as we change properties, wasting much memory.
    • Add dependency check for XSL module for hotspot_status.php.
    • Some work towards respecting the coding style: http://dev.wifidog.org/wiki/doc/developer/CodingStandard
    • wifidog/admin/index.php: Delete admin page. There is no longuer a concept of a separate admin section. Menu will depend on your access level.
  • 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 $current_node_id = 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 :: $current_node_id != null && $real_node_only == false)
120        {
121            $object = self::getObject(self :: $current_node_id);
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 purpuses, among other.
131     * @param $node Node.  The new current node.
132     * @return true      */
133    static function setCurrentNode(Node $node)
134    {
135        self :: $current_node_id = $node->GetId();
136        return true;
137    }
138
139    /** 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
140     * @param    * @return a Node object, or null if it can't be found.
141     */
142    public static function getCurrentRealNode()
143    {
144        static $currentRealNode;
145        static $currentRealNodeComputed;
146        if(!isset($currentRealNodeComputed))
147        {
148            $currentRealNodeComputed=true;
149            $db = AbstractDb::getObject();
150            $sql = "SELECT node_id, last_heartbeat_ip from nodes WHERE last_heartbeat_ip='$_SERVER[REMOTE_ADDR]' ORDER BY last_heartbeat_timestamp DESC";
151            $node_rows = null;
152            $db->execSql($sql, $node_rows, false);
153            $num_match = count($node_rows);
154            if ($num_match == 0)
155            {
156
157                // User is not physically connected to a node
158                $currentRealNode = null;
159            }
160            else
161            if ($num_match = 1)
162            {
163                // Only a single node matches, the user is presumed to be there
164                $currentRealNode = self::getObject($node_rows[0]['node_id']);
165            }
166            else
167            {
168                /* We have more than one node matching the IP (the nodes are behind the same NAT).
169                 * We will try to discriminate by finding which node the user last authenticated against.
170                 * If the IP matches, we can be pretty certain the user is there.
171                 */
172                $currentRealNode = null;
173                $current_user = User :: getCurrentUser();
174                if ($current_user != null)
175                {
176                    $current_user_id = $current_user->getId();
177                    $_SERVER['REMOTE_ADDR'];
178                    $sql = "SELECT node_id, last_heartbeat_ip from connections NATURAL JOIN nodes WHERE user_id='$current_user_id' ORDER BY last_updated DESC ";
179                    $db->execSql($sql, $node_rows, false);
180                    $node_row = $node_rows[0];
181                    if ($node_row != null && $node_row['last_heartbeat_ip'] == $_SERVER['REMOTE_ADDR'])
182                    {
183                        $currentRealNode = self::getObject($node_row['node_id']);
184                    }
185                }
186            }
187        }
188
189        return $currentRealNode;
190    }
191
192    public function delete(& $errmsg)
193    {
194        $retval = false;
195        $user = User :: getCurrentUser();
196        if ($user->DEPRECATEDisSuperAdmin()) {
197            $db = AbstractDb::getObject();
198            $id = $db->escapeString($this->getId());
199            if (!$db->execSqlUpdate("DELETE FROM nodes WHERE node_id='{$id}'", false))
200            {
201                $errmsg = _('Could not delete node!');
202            }
203            else
204            {
205                $retval = true;
206            }
207        }
208        else
209        {
210            $errmsg = _('Access denied!');
211        }
212
213        return $retval;
214    }
215
216    /**
217     * Create a new Node in the database
218     *
219     * @param string $gw_id The Id of the gatewqay to be associated with
220     * thisnode. If not present, a dummy value will be assigned.
221     * @param object $network Network object.  The node's network.  If not
222     *                        present, the current Network will be assigned
223     *
224     * @return mixed The newly created Node object, or null if there was
225     *               an error
226     *
227     * @static
228     * @access public
229     */
230    public static function createNewObject($gw_id = null, $network = null)
231    {
232        $db = AbstractDb::getObject();
233        if (empty ($gw_id)) {
234            $gw_id = $db->escapeString(_('PUT_GATEWAY_ID_HERE'));
235        }
236        else
237        {
238            $gw_id = $db->escapeString($gw_id);
239        }
240        $node_id = get_guid();
241
242
243        if (empty ($network)) {
244            $network = Network::getCurrentNetwork();
245        }
246
247        $network_id = $db->escapeString($network->getId());
248
249        $node_deployment_status = $db->escapeString("IN_PLANNING");
250        $node_name = _("New node");
251        $duplicate = null;
252        try{
253            $duplicate = Node::getObjectByGatewayId($gw_id);
254        }
255        catch (Exception $e)
256        {
257        }
258        if ($duplicate) {
259            throw new Exception(sprintf(_('Sorry, a node for the gateway %s already exists.'),$gw_id));
260        }
261
262        $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')";
263
264        if (!$db->execSqlUpdate($sql, false)) {
265            throw new Exception(_('Unable to insert new node into database!'));
266        }
267
268        $object = self::getObject($node_id);
269
270        return $object;
271    }
272
273    /** Get an interface to pick a node.
274     * @param $user_prefix A identifier provided by the programmer to recognise it's generated html form
275     *
276     * @param $sql_additional_where Addidional where conditions to restrict the candidate objects
277     * @param $type_interface:  select, select_multiple or table
278     * @param $selectedNodes; Node object or array of node objects to be pre-selected (not
279     * supported by type_interface=table)
280     * * @return html markup
281     */
282    public static function getSelectNodeUI($user_prefix, $sql_additional_join = null, $sql_additional_where = null,$selectedNodes = null, $type_interface = "select")
283    {
284        $db = AbstractDb::getObject();
285        $html = '';
286        $name = "{$user_prefix}";
287
288        $_deploymentStatuses = array(
289        "DEPLOYED" => _("Deployed"),
290        "IN_PLANNING" => _("In planning"),
291        "IN_TESTING" => _("In testing"),
292        "NON_WIFIDOG_NODE" => _("Non-Wifidog node"),
293        "PERMANENTLY_CLOSED" => _("Permanently closed"),
294        "TEMPORARILY_CLOSED" => _("Temporarily closed")
295        );
296
297        $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)";
298        $node_rows = null;
299        $db->execSql($sql, $node_rows, false);
300
301        if ($node_rows != null) {
302            Utils :: natsort2d($node_rows, "name");
303            if ($type_interface != "table") {
304                $i = 0;
305                foreach ($node_rows as $node_row)
306                {
307                    $tab[$i][0] = $node_row['node_id'];
308                    //$tab[$i][1] = sprintf(_("%s (gw: %s)"),$node_row['name'],$node_row['gw_id']);
309                    $tab[$i][1] = $node_row['name'];
310                    $i ++;
311                }
312                if($type_interface == "select_multiple"){
313                    $select_options="MULTIPLE SIZE=6";
314                }
315                else
316                {
317                    $select_options=null;
318                }
319                //pretty_print_r($selectedNodes);
320                if(is_array($selectedNodes)){
321                    $selectedPrimaryKey=array();
322                    foreach($selectedNodes as $node){
323                        $selectedPrimaryKey[]=$node->getId();
324                    }
325
326                }
327                else if($selectedNodes instanceof Node){
328                    $selectedPrimaryKey=$selectedNodes->getId();
329                }
330                else{
331                    $selectedPrimaryKey=null;
332                }
333                $html .= FormSelectGenerator :: generateFromArray($tab, $selectedPrimaryKey, $name, null, false, null, $select_options);
334            } else {
335                $html .= "<fieldset>\n    <legend>Node List</legend>\n";
336                $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";
337                $html .= "    <!--[if IE]><style type='text/css'>#node_list_div table.scrollable>tbody { height: 15px; }</style><![endif]-->\n";
338                $html .= "    <script src='" . BASE_URL_PATH . "js/filtertable.js' type='text/javascript' language='javascript' charset='utf-8'></script>\n";
339                $html .= "    <script src='" . BASE_URL_PATH . "js/sorttable.js' type='text/javascript' language='javascript' charset='utf-8'></script>\n";
340                $html .= "    <div id='node_list_div' class='node_admin tableContainer'>\n";
341                $html .= "        <table id='nodes_list' class='node_admin filterable scrollable sortable'>\n\n";
342                $html .= "            <thead class='fixedHeader'>\n";
343                $html .= "<tr class='nofilter'>\n";
344                $html .= "<th>"._("Node Name")."</th>\n";
345                $html .= "<th>"._("Gateway ID")."</th>\n";
346                $html .= "<th>"._("Deployment Status")."</th>\n";
347                $html .= "</tr>\n";
348                $html .= "</thead>\n";
349                $html .= "<tbody>";
350
351                $i = 0;
352                foreach ($node_rows as $node_row)
353                {
354                    $href = GENERIC_OBJECT_ADMIN_ABS_HREF."?object_id={$node_row['node_id']}&object_class=Node&action=edit";
355                    $_deployStatusNode = $node_row['node_deployment_status'];
356                    $html .= "<tr class='row' onclick=\"javascript:location.href='{$href}'\">\n";
357                    $html .= "<td>{$node_row['name']}<noscript>(<a href='{$href}'>edit</a>)</noscript></td>\n";
358                    $html .= "<td>{$node_row['gw_id']}</td>\n";
359                    $html .= "<td>{$_deploymentStatuses[$_deployStatusNode]}</td>\n";
360                    $html .= "</tr>\n";
361                }
362                $html .= "            </tbody>\n        </table>\n";
363                $html .= "    </div>\n";
364                $html .= "</fieldset>\n";
365
366            }
367        } else {
368            $html .= "<div class='warningmsg'>"._("Sorry, no nodes available in the database")."</div>\n";
369        }
370        return $html;
371    }
372
373
374    /** Get the selected Network object.
375     * @param $user_prefix A identifier provided by the programmer to recognise it's generated form
376     * @return the node object
377     */
378    static function processSelectNodeUI($user_prefix)
379    {
380        $object = null;
381        $name = "{$user_prefix}";
382        return self::getObject($_REQUEST[$name]);
383    }
384
385    /** Get an interface to create a new node.
386     * @param $network Optional:  The network to which the new node will belong,
387     * if absent, the user will be prompted.
388     * @return html markup
389     */
390    public static function getCreateNewObjectUI($network = null)
391    {
392        $html = '';
393        $html .= _("Add a new node for the gateway ID")." \n";
394        $name = "new_node_gw_id";
395        $html .= "<input type='text' size='10' name='{$name}'>\n";
396        if ($network)
397        {
398            $name = "new_node_network_id";
399            $html .= "<input type='hidden' name='{$name}' value='{$network->getId()}'>\n";
400        }
401        else
402        {
403            $html .= " "._("in ")." \n";
404            $html .= Network :: getSelectUI('new_node');
405        }
406        return $html;
407
408    }
409
410    /**
411     * Process the new object interface.
412     *
413     * Will return the new object if the user has the credentials and the form was fully filled.
414     * @return the node object or null if no new node was created.
415     */
416    public static function processCreateNewObjectUI()
417    {
418        // Init values
419        $retval = null;
420        $name = "new_node_gw_id";
421
422        if (!empty ($_REQUEST[$name])) {
423            $gw_id = $_REQUEST[$name];
424        }
425        else
426        {
427            $gw_id = null;
428        }
429        $name = "new_node_network_id";
430
431        if (!empty ($_REQUEST[$name])) {
432            $network = Network::getObject($_REQUEST[$name]);
433        } else {
434            $network = Network::processSelectUI('new_node');
435        }
436
437        if ($network) {
438            try {
439                if (!$network->DEPRECATEDhasAdminAccess(User :: getCurrentUser())) {
440                    throw new Exception(_("Access denied"));
441                }
442            } catch (Exception $e) {
443                $ui = MainUI::getObject();
444                $ui->displayError($e->getMessage(), false);
445                exit;
446            }
447
448            $retval = self::createNewObject($gw_id, $network);
449        }
450
451        return $retval;
452    }
453
454    /**
455     * Get an interface to select the deployment status
456     *
457     * @param string $user_prefix A identifier provided by the programmer to
458     *                            recognise it's generated html form
459     *
460     * @return string HTML markup
461     */
462    public function getSelectDeploymentStatus($user_prefix)
463    {
464         
465        $db = AbstractDb::getObject();
466
467        // Init values
468        $html = "";
469        $status_list = null;
470        $tab = array();
471
472        $name = "{$user_prefix}";
473        $db->execSql("SELECT node_deployment_status FROM node_deployment_status", $status_list, false);
474
475        if ($status_list == null) {
476            throw new Exception(_("No deployment statuses could be found in the database"));
477        }
478
479        foreach ($status_list as $status) {
480            $_statusvalue = $status['node_deployment_status'];
481            $tab[] = array($_statusvalue, $this->_deploymentStatuses["$_statusvalue"]);
482        }
483
484        $html .= FormSelectGenerator::generateFromArray($tab, $this->getDeploymentStatus(), $name, null, false);
485
486        return $html;
487    }
488
489    /**
490     * Get the selected deployment status
491     *
492     * @param string $user_prefix An identifier provided by the programmer to
493     *                            recognise it's generated form
494     *
495     * @return string The deployment status
496
497     */
498    public function processSelectDeploymentStatus($user_prefix)
499    {
500        $object = null;
501        $name = "{$user_prefix}";
502        return $_REQUEST[$name];
503    }
504
505    /** @param $id The id of the node
506     * @param $idType 'NODE_ID' or 'GATEWAY_ID'*/
507    private function __construct($id, $idType='NODE_ID')
508    {
509        $db = AbstractDb::getObject();
510        $this->mDb = & $db;
511
512        $id_str = $db->escapeString($id);
513        switch ($idType) {
514            case 'NODE_ID': $sqlWhere = "node_id='$id_str'";
515            break;
516            case 'GATEWAY_ID': $sqlWhere = "gw_id='$id_str'";
517            break;
518            default:
519                throw new exception('Unknown idType parameter');
520        }
521        $sqlWhere =
522        $sql = "SELECT * FROM nodes WHERE $sqlWhere";
523        $row = null;
524        $db->execSqlUniqueRes($sql, $row, false);
525        if ($row == null)
526        {
527            throw new Exception(sprintf(_("The node with %s: %s could not be found in the database!"), $idType, $id_str));
528        }
529
530        $this->_deploymentStatuses = array(
531        "DEPLOYED" => _("Deployed"),
532        "IN_PLANNING" => _("In planning"),
533        "IN_TESTING" => _("In testing"),
534        "NON_WIFIDOG_NODE" => _("Non-Wifidog node"),
535        "PERMANENTLY_CLOSED" => _("Permanently closed"),
536        "TEMPORARILY_CLOSED" => _("Temporarily closed")
537        );
538
539        $this->_row = $row;
540        $this->id = $row['node_id'];
541    }
542
543    function __toString() {
544        return $this->getName();
545    }
546
547    function getId()
548    {
549        return $this->id;
550    }
551
552    /** Get the id of the gateway associated with this node */
553    function getGatewayId()
554    {
555        return $this->_row['gw_id'];
556    }
557    /** Change the gateway ID of the gateway asociated with this node.
558     * @param $id, string, the new node id.
559     * @return true on success, false on failure. Check this,
560     * as it's possible that someone will enter an existing id, especially
561     * if the MAC address is used and hardware is recycled.
562     */
563    function setGatewayId($id)
564    {
565        $id = $this->mDb->escapeString($id);
566        $retval = $this->mDb->execSqlUpdate("UPDATE nodes SET gw_id = '{$id}' WHERE node_id = '{$this->getId()}'");
567        if ($retval)
568        {
569            $this->refresh();
570        }
571        return $retval;
572    }
573
574    /** Gets the Network to which the node belongs
575     * @return Network object (never returns null)
576     */
577    public function getNetwork()
578    {
579        return Network :: getObject($this->_row['network_id']);
580    }
581
582    /** Get a GisPoint object ; altide is not supported yet
583     */
584    function getGisLocation()
585    {
586        // Altitude is not supported yet
587        return new GisPoint($this->_row['latitude'], $this->_row['longitude'], 0);
588    }
589
590    function setGisLocation($pt)
591    {
592        if (!empty ($pt))
593        {
594            $lat = $this->mDb->escapeString($pt->getLatitude());
595            $long = $this->mDb->escapeString($pt->getLongitude());
596
597            if (!empty ($lat) && !empty ($long))
598            $this->mDb->execSqlUpdate("UPDATE nodes SET latitude = $lat, longitude = $long WHERE node_id = '{$this->getId()}'");
599            else
600            $this->mDb->execSqlUpdate("UPDATE nodes SET latitude = NULL, longitude = NULL WHERE node_id = '{$this->getId()}'");
601            $this->refresh();
602        }
603    }
604
605    /** Return the name of the node
606     */
607    function getName()
608    {
609        return $this->_row['name'];
610    }
611
612    function setName($name)
613    {
614        $name = $this->mDb->escapeString($name);
615        $this->mDb->execSqlUpdate("UPDATE nodes SET name = '{$name}' WHERE node_id = '{$this->getId()}'");
616        $this->refresh();
617    }
618
619    function getCreationDate()
620    {
621        return $this->_row['creation_date'];
622    }
623
624    function setCreationDate($creation_date)
625    {
626        $creation_date = $this->mDb->escapeString($creation_date);
627        $this->mDb->execSqlUpdate("UPDATE nodes SET creation_date = '{$creation_date}' WHERE node_id = '{$this->getId()}'");
628        $this->refresh();
629    }
630
631    function getWebSiteURL()
632    {
633        return $this->_row['home_page_url'];
634    }
635
636    function setWebSiteUrl($url)
637    {
638        $url = $this->mDb->escapeString($url);
639        $this->mDb->execSqlUpdate("UPDATE nodes SET home_page_url = '{$url}' WHERE node_id = '{$this->getId()}'");
640        $this->refresh();
641    }
642
643    function getDescription()
644    {
645        return $this->_row['description'];
646    }
647
648    function setDescription($description)
649    {
650        $description = $this->mDb->escapeString($description);
651        $this->mDb->execSqlUpdate("UPDATE nodes SET description = '{$description}' WHERE node_id = '{$this->getId()}'");
652        $this->refresh();
653    }
654
655    function getMapURL()
656    {
657        return $this->_row['map_url'];
658    }
659
660    function setMapURL($url)
661    {
662        $url = $this->mDb->escapeString($url);
663        $this->mDb->execSqlUpdate("UPDATE nodes SET map_url = '{$url}' WHERE node_id = '{$this->getId()}'");
664        $this->refresh();
665    }
666
667    public function getCivicNumber()
668    {
669        return $this->_row['civic_number'];
670    }
671
672    public function setCivicNumber($civic_number)
673    {
674        $civic_number = $this->mDb->escapeString($civic_number);
675        $this->mDb->execSqlUpdate("UPDATE nodes SET civic_number = '{$civic_number}' WHERE node_id = '{$this->getId()}'");
676        $this->refresh();
677    }
678
679    public function getStreetName()
680    {
681        return $this->_row['street_name'];
682    }
683
684    public function setStreetName($street_name)
685    {
686        $street_name = $this->mDb->escapeString($street_name);
687        $this->mDb->execSqlUpdate("UPDATE nodes SET street_name = '{$street_name}' WHERE node_id = '{$this->getId()}'");
688        $this->refresh();
689    }
690
691    public function getCity()
692    {
693        return $this->_row['city'];
694    }
695
696    public function setCity($city)
697    {
698        $city = $this->mDb->escapeString($city);
699        $this->mDb->execSqlUpdate("UPDATE nodes SET city = '{$city}' WHERE node_id = '{$this->getId()}'");
700        $this->refresh();
701    }
702
703    public function getProvince()
704    {
705        return $this->_row['province'];
706    }
707
708    public function setProvince($province)
709    {
710        $province = $this->mDb->escapeString($province);
711        $this->mDb->execSqlUpdate("UPDATE nodes SET province = '{$province}' WHERE node_id = '{$this->getId()}'");
712        $this->refresh();
713    }
714
715    public function getCountry()
716    {
717        return $this->_row['country'];
718    }
719
720    protected function setCountry($country)
721    {
722        $country = $this->mDb->escapeString($country);
723        $this->mDb->execSqlUpdate("UPDATE nodes SET country = '{$country}' WHERE node_id = '{$this->getId()}'");
724        $this->refresh();
725    }
726
727    public function getPostalCode()
728    {
729        return $this->_row['postal_code'];
730    }
731
732    public function setPostalCode($postal_code)
733    {
734        $postal_code = $this->mDb->escapeString($postal_code);
735        $this->mDb->execSqlUpdate("UPDATE nodes SET postal_code = '{$postal_code}' WHERE node_id = '{$this->getId()}'");
736        $this->refresh();
737    }
738
739    function getTelephone()
740    {
741        return $this->_row['public_phone_number'];
742    }
743
744    function setTelephone($phone)
745    {
746        $phone = $this->mDb->escapeString($phone);
747        $this->mDb->execSqlUpdate("UPDATE nodes SET public_phone_number = '{$phone}' WHERE node_id = '{$this->getId()}'");
748        $this->refresh();
749    }
750
751    function getTransitInfo()
752    {
753        return $this->_row['mass_transit_info'];
754    }
755
756    function setTransitInfo($transit_info)
757    {
758        $transit_info = $this->mDb->escapeString($transit_info);
759        $this->mDb->execSqlUpdate("UPDATE nodes SET mass_transit_info = '{$transit_info}' WHERE node_id = '{$this->getId()}'");
760        $this->refresh();
761    }
762
763    function getEmail()
764    {
765        return $this->_row['public_email'];
766    }
767
768    function setEmail($email)
769    {
770        $email = $this->mDb->escapeString($email);
771        $this->mDb->execSqlUpdate("UPDATE nodes SET public_email = '{$email}' WHERE node_id = '{$this->getId()}'");
772        $this->refresh();
773    }
774
775    function getDeploymentStatus()
776    {
777        return $this->_row['node_deployment_status'];
778    }
779
780    function setDeploymentStatus($status)
781    {
782        $status = $this->mDb->escapeString($status);
783        $this->mDb->execSqlUpdate("UPDATE nodes SET node_deployment_status = '{$status}' WHERE node_id = '{$this->getId()}'");
784        $this->refresh();
785    }
786
787    function getLastPaged()
788    {
789        return $this->_row['last_paged'];
790    }
791
792    function setLastPaged($last_paged)
793    {
794        $this->mDb->execSqlUpdate("UPDATE nodes SET last_paged = {$last_paged}::abstime WHERE node_id = '{$this->getId()}'");
795        $this->refresh();
796    }
797
798    function getLastHeartbeatIP()
799    {
800        return $this->_row['last_heartbeat_ip'];
801    }
802
803    function getLastHeartbeatUserAgent()
804    {
805        return $this->_row['last_heartbeat_user_agent'];
806    }
807
808    function getLastHeartbeatTimestamp()
809    {
810        return $this->_row['last_heartbeat_timestamp'];
811    }
812
813    function setLastHeartbeatTimestamp($timestamp)
814    {
815        $this->mDb->execSqlUpdate("UPDATE nodes SET last_heartbeat_timestamp = '{$timestamp}' WHERE node_id = '{$this->getId()}'");
816        $this->refresh();
817    }
818
819    /** Is the node a Splash Only node?  Will only return true if the Network configuration allows it.
820     * @return true or false */
821    public function isSplashOnly()
822    {
823        return $this->getNetwork()->getSplashOnlyNodesAllowed() && $this->isConfiguredSplashOnly();
824    }
825
826    /** Is the node configured as a Splash Only node?  This is NOT the same as isSplashOnly().
827     * This is the getter for the configuration set in the database for this node.
828     * For the node to actually be splash only, this AND the network
829     * gonfiguration must match.
830     * @return true or false */
831    public function isConfiguredSplashOnly()
832    {
833        return (($this->_row['is_splash_only_node'] == 't') ? true : false);
834    }
835
836    /** Set if this node should be a splash-only (no login) node (if enabled in Network configuration)
837     * @param $value The new value, true or false
838     * @return true on success, false on failure */
839    function setIsConfiguredSplashOnly($value)
840    {
841        $retval = true;
842        if ($value != $this->isConfiguredSplashOnly())
843        {
844            $db = AbstractDb::getObject();
845            $value ? $value = 'TRUE' : $value = 'FALSE';
846            $retval = $db->execSqlUpdate("UPDATE nodes SET is_splash_only_node = {$value} WHERE node_id = '{$this->getId()}'", false);
847            $this->refresh();
848        }
849        return $retval;
850    }
851
852    /** The url to show instead of the portal.  If empty, the portal is shown
853     Must be enabled in the Network configuration to have any effect
854     @return a string */
855    function getCustomPortalRedirectUrl()
856    {
857        return $this->_row['custom_portal_redirect_url'];
858    }
859
860    /** The url to show instead of the portal.  If empty, the portal is shown
861     Must be enabled in the Network configuration to have any effect
862     @return true on success, false on failure */
863    function setCustomPortalRedirectUrl($value)
864    {
865        $retval = true;
866        if ($value != $this->getCustomPortalRedirectUrl())
867        {
868            $db = AbstractDb::getObject();
869            $value = $db->escapeString($value);
870            $retval = $db->execSqlUpdate("UPDATE nodes SET custom_portal_redirect_url = '{$value}' WHERE node_id = '{$this->getId()}'", false);
871            $this->refresh();
872        }
873        return $retval;
874    }
875
876    /**
877     * Retrieves the admin interface of this object
878     *
879     * @return string The HTML fragment for this interface
880     *
881     * @access public
882     *
883     * @todo Most of this code will be moved to Hotspot class when the
884     *       abtraction will be completed
885     */
886    public function getAdminUI()
887    {
888        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
889        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
890        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
891        Security::requireAnyPermission($permArray);
892        require_once('classes/InterfaceElements.php');
893        require_once('classes/Stakeholder.php');
894        // Init values
895        $html = '';
896
897        // Get information about the network
898        $network = $this->getNetwork();
899
900        // Check if user is a admin
901        $_userIsAdmin = User::getCurrentUser()->DEPRECATEDisSuperAdmin();
902
903        $node_id = $this->getId();
904
905        /*
906         * Check for a warning message
907         */
908        if ($this->_warningMessage != "") {
909            $html .= "<div class='errormsg'>".$this->_warningMessage."</div>\n";
910        }
911
912        /*
913         * Begin with admin interface
914         */
915        $html .= "<fieldset class='admin_container ".get_class($this)."'>\n";
916        $html .= "<legend>"._("Edit a node")."</legend>\n";
917        $html .= "<ul class='admin_element_list'>\n";
918
919        /*
920         * Display stats
921         */
922        $_title = _("Statistics");
923        $_data = InterfaceElements::generateInputSubmit("node_" . $this->id . "_get_stats", _("Get access statistics"), "node_get_stats_submit");
924        $html .= InterfaceElements::generateAdminSectionContainer("node_get_stats", $_title, $_data);
925
926        /*
927         * Information about the node
928         */
929        $_html_node_information = array();
930
931        // Gateway ID
932        $_title = _("Gateway ID");
933        if (Security::hasPermission(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this)) {
934            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gw_id", $this->getGatewayId(), "gw_id_input");
935        } else {
936            $_data  = htmlspecialchars($this->getGatewayId(), ENT_QUOTES);
937            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_gw_id", $this->getGatewayId());
938        }
939        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("gateway_id", $_title, $_data);
940
941        //Node content
942        $_html_content = array();
943        $_title = _("Node content");
944        $_data = Content::getLinkedContentUI("node_" . $node_id . "_content", "node_has_content", "node_id", $this->id, "portal");
945        $html .= InterfaceElements::generateAdminSectionContainer("node_content", $_title, $_data);
946
947        // Name
948        $_title = _("Name");
949        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_name", $this->getName(), "node_name_input");
950        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_name", $_title, $_data);
951
952        // Creation date
953        $_title = _("Creation date");
954        if ($_userIsAdmin) {
955            $_data = DateTimeWD::getSelectDateTimeUI(new DateTimeWD($this->getCreationDate()), "node_" . $node_id . "_creation_date", DateTimeWD::INTERFACE_DATETIME_FIELD, "node_creation_date_input");
956        } else {
957            $_data  = htmlspecialchars($this->getCreationDate(), ENT_QUOTES);
958            $_data .= InterfaceElements::generateInputHidden("node_" . $node_id . "_creation_date", $this->getCreationDate());
959        }
960        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_creation_date", $_title, $_data);
961
962        // Description
963        $_title = _("Description");
964        $name = "node_" . $node_id . "_description";
965        $_data = "<textarea name='$name' cols=80 rows=5 id='node_description_textarea'>\n".$this->getDescription()."\n</textarea>\n";
966        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_description", $_title, $_data);
967
968        // Civic number
969        $_title = _("Civic number");
970        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_civic_number", $this->getCivicNumber(), "node_civic_number_input");
971        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_civic_number", $_title, $_data);
972
973        // Street name
974        $_title = _("Street name");
975        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_street_name", $this->getStreetName(), "node_street_name_input");
976        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_street_name", $_title, $_data);
977
978        // City
979        $_title = _("City");
980        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_city", $this->getCity(), "node_city_input");
981        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_city", $_title, $_data);
982
983        // Province
984        $_title = _("Province / State");
985        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_province", $this->getProvince(), "node_province_input");
986        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_province", $_title, $_data);
987
988        // Postal Code
989        $_title = _("Postal code");
990        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_postal_code", $this->getPostalCode(), "node_postal_code_input");
991        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_postal_code", $_title, $_data);
992
993        // Country
994        $_title = _("Country");
995        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_country", $this->getCountry(), "node_country_input");
996        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_country", $_title, $_data);
997
998        // Public phone #
999        $_title = _("Public phone number");
1000        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_phone", $this->getTelephone(), "node_public_phone_input");
1001        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_phone", $_title, $_data);
1002
1003        // Public mail
1004        $_title = _("Public email");
1005        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_public_email", $this->getEmail(), "node_public_email_input");
1006        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_public_email", $_title, $_data);
1007
1008        // Homepage URL
1009        $_title = _("Homepage URL");
1010        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_homepage_url", $this->getWebSiteURL(), "node_homepage_url_input");
1011        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_homepage_url", $_title, $_data);
1012
1013        // Mass transit info
1014        $_title = _("Mass transit info");
1015        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_mass_transit_info", $this->getTransitInfo(), "node_mass_transit_info_input");
1016        $_html_node_information[] = InterfaceElements::generateAdminSectionContainer("node_mass_transit_info", $_title, $_data);
1017
1018        // Build section
1019        $html .= InterfaceElements::generateAdminSectionContainer("node_information", _("Information about the node"), implode(null, $_html_node_information));
1020
1021        /*
1022         * Node GIS data
1023         */
1024        $_html_node_gis_data = array();
1025        $gis_point = $this->getGisLocation();
1026
1027        // Latitude
1028        $_title = _("Latitude");
1029        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_latitude", $gis_point->getLatitude(), "node_" . $node_id . "_gis_latitude");
1030        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_latitude", $_title, $_data);
1031
1032        // Latitude
1033        $_title = _("Longitude");
1034        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_gis_longitude", $gis_point->getLongitude(), "node_" . $node_id . "_gis_longitude");
1035        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_longitude", $_title, $_data);
1036
1037        // Call the geocoding service, if Google Maps is enabled then use Google Maps to let the user choose a more precise location
1038        if (defined('GMAPS_HOTSPOTS_MAP_ENABLED') && GMAPS_HOTSPOTS_MAP_ENABLED === true) {
1039            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1040            $_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');"));
1041            $_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";
1042        } else {
1043            $_data  = InterfaceElements::generateInputSubmit("geocode_only", _("Geocode the address or postal code above"), "geocode_only_submit");
1044            $_data .= "<div class='admin_section_hint' id='node_gis_geocode_hint'>". "(" . _("Use a geocoding service") . ")" ."</div>\n";
1045        }
1046
1047        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_gis_geocode", "", $_data);
1048
1049        // Map URL
1050        $_title = _("Map URL");
1051        $_data = InterfaceElements::generateInputText("node_" . $node_id . "_map_url", $this->getMapURL(), "node_map_url_input");
1052        $_html_node_gis_data[] = InterfaceElements::generateAdminSectionContainer("node_map_url", $_title, $_data);
1053
1054        // Build section
1055        $html .= InterfaceElements::generateAdminSectionContainer("node_gis_data", _("GIS data"), implode(null, $_html_node_gis_data));
1056
1057        /*
1058         * Node configuration section
1059         */
1060        $_html_node_config = array();
1061
1062        // Deployment status
1063        $_title = _("Node deployment status");
1064        $_data = $this->getSelectDeploymentStatus("node_" . $node_id . "_deployment_status");
1065        $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_deployment_status", $_title, $_data);
1066
1067        //  is_splash_only_node
1068        if ($network->getSplashOnlyNodesAllowed()) {
1069            $_title = _("Is this node splash-only (no login)?");
1070            $_data = InterfaceElements::generateInputCheckbox("node_" . $node_id . "_is_splash_only_node", "", _("Yes"), $this->isConfiguredSplashOnly(), "node_is_splash_only_node_radio");
1071            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_is_splash_only_node", $_title, $_data);
1072        }
1073
1074        // custom_portal_redirect_url
1075        if ($network->getCustomPortalRedirectAllowed()) {
1076            $_title = _("URL to show instead of the portal");
1077            $_data = InterfaceElements::generateInputText("node_" . $node_id . "_custom_portal_redirect_url", $this->getCustomPortalRedirectUrl(), "node_custom_portal_redirect_url_input");
1078            $_data .= _("If this is not empty, the portal will be disabled and this URL will be shown instead");
1079            $_html_node_config[] = InterfaceElements::generateAdminSectionContainer("node_custom_portal_redirect_url", $_title, $_data);
1080        }
1081
1082        // Build section
1083        $html .= InterfaceElements::generateAdminSectionContainer("node_config", _("Node configuration"), implode(null, $_html_node_config));
1084
1085        /*
1086         * Access rights
1087         */
1088        if ($_userIsAdmin) {
1089            require_once('classes/Stakeholder.php');
1090            $html_access_rights = Stakeholder::getAssignStakeholdersUI($this);
1091            $html .= InterfaceElements::generateAdminSectionContainer("access_rights", _("Access rights"), $html_access_rights);
1092        }
1093
1094        $html .= "</ul>\n";
1095        $html .= "</fieldset>";
1096
1097        return $html;
1098    }
1099
1100    /**
1101     * Process admin interface of this object.
1102     *
1103     * @return void
1104     *
1105     * @access public
1106     */
1107    public function processAdminUI()
1108    {
1109        require_once('classes/Stakeholder.php');
1110        $user = User::getCurrentUser();
1111        //pretty_print_r($_REQUEST);
1112        $permArray[]=array(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG'), $this->getNetwork());
1113        $permArray[]=array(Permission::P('NODE_PERM_EDIT_CONFIG'), $this);
1114        $permArray[]=array(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this);
1115        Security::requireAnyPermission($permArray);
1116        // Check if user is a admin
1117        $_userIsAdmin = User::getCurrentUser()->DEPRECATEDisSuperAdmin();
1118
1119        // Information about the node
1120
1121        $node_id = $this->getId();
1122
1123        // Gateway Id
1124        if(Security::hasPermission(Permission::P('NODE_PERM_EDIT_GATEWAY_ID'), $this)) {
1125            $name = "node_" . $node_id . "_gw_id";
1126            $this->setGatewayId($_REQUEST[$name]);
1127        }
1128        // Content processing
1129        $name = "node_{$node_id}_content";
1130        Content::processLinkedContentUI($name, 'node_has_content', 'node_id', $this->id);
1131
1132        // Name
1133        if ($_userIsAdmin) {
1134            $name = "node_".$node_id."_name";
1135            $this->setName($_REQUEST[$name]);
1136        } else {
1137            $this->setName($this->getName());
1138        }
1139
1140        // Creation date
1141        if ($_userIsAdmin) {
1142            $name = "node_".$node_id."_creation_date";
1143            $this->setCreationDate(DateTimeWD::processSelectDateTimeUI($name, DateTimeWD :: INTERFACE_DATETIME_FIELD)->getIso8601FormattedString());
1144        } else {
1145            $this->setCreationDate($this->getCreationDate());
1146        }
1147
1148        // Homepage URL
1149        $name = "node_".$node_id."_homepage_url";
1150        $this->setWebSiteUrl($_REQUEST[$name]);
1151
1152        // Description
1153        $name = "node_".$node_id."_description";
1154        $this->setDescription($_REQUEST[$name]);
1155
1156        // Map URL
1157        $name = "node_".$node_id."_map_url";
1158        $this->setMapUrl($_REQUEST[$name]);
1159
1160        // Civic number
1161        $name = "node_".$node_id."_civic_number";
1162        $this->setCivicNumber($_REQUEST[$name]);
1163
1164        // Street name
1165        $name = "node_".$node_id."_street_name";
1166        $this->setStreetName($_REQUEST[$name]);
1167
1168        // City
1169        $name = "node_".$node_id."_city";
1170        $this->setCity($_REQUEST[$name]);
1171
1172        // Province
1173        $name = "node_".$node_id."_province";
1174        $this->setProvince($_REQUEST[$name]);
1175
1176        // Postal Code
1177        $name = "node_".$node_id."_postal_code";
1178        $this->setPostalCode($_REQUEST[$name]);
1179
1180        // Country
1181        $name = "node_".$node_id."_country";
1182        $this->setCountry($_REQUEST[$name]);
1183
1184        // Public phone #
1185        $name = "node_".$node_id."_public_phone";
1186        $this->setTelephone($_REQUEST[$name]);
1187
1188        // Public mail
1189        $name = "node_".$node_id."_public_email";
1190        $this->setEmail($_REQUEST[$name]);
1191
1192        // Mass transit info
1193        $name = "node_".$node_id."_mass_transit_info";
1194        $this->setTransitInfo($_REQUEST[$name]);
1195
1196        // GIS data
1197        // Get a geocoder for a given country
1198        if (!empty ($_REQUEST['geocode_only']))
1199        {
1200            $geocoder = AbstractGeocoder :: getGeocoder($this->getCountry());
1201            if ($geocoder != null)
1202            {
1203                $geocoder->setCivicNumber($this->getCivicNumber());
1204                $geocoder->setStreetName($this->getStreetName());
1205                $geocoder->setCity($this->getCity());
1206                $geocoder->setProvince($this->getProvince());
1207                $geocoder->setPostalCode($this->getPostalCode());
1208                if ($geocoder->validateAddress() === true)
1209                {
1210                    if (($point = $geocoder->getGisLocation()) !== null)
1211                    $this->setGisLocation($point);
1212                    else
1213                    $this->_warningMessage = _("It appears that the Geocoder could not be reached or could not geocode the given address.");
1214                }
1215                else
1216                $this->_warningMessage = _("You must enter a valid address.");
1217            }
1218            else
1219            {
1220                $this->_warningMessage = _("Unable to create geocoder.  Are you sure you set the country?");
1221            }
1222        }
1223        else
1224        {
1225            // Use what has been set by the user.
1226            $gis_lat_name = "node_".$node_id."_gis_latitude";
1227            $gis_long_name = "node_".$node_id."_gis_longitude";
1228            $this->setGisLocation(new GisPoint($_REQUEST[$gis_lat_name], $_REQUEST[$gis_long_name], .0));
1229        }
1230
1231        // Statistics
1232        $name = "node_{$this->id}_get_stats";
1233        if (!empty ($_REQUEST[$name]))
1234        header("Location: stats.php?node_id=".urlencode($this->getId()));
1235
1236        // Node configuration section
1237
1238        $network = $this->getNetwork();
1239
1240        // Deployment status
1241        $name = "node_".$node_id."_deployment_status";
1242        $this->setDeploymentStatus(self :: processSelectDeploymentStatus($name));
1243
1244        //  is_splash_only_node
1245        if ($network->getSplashOnlyNodesAllowed())
1246        {
1247            $name = "node_".$node_id."_is_splash_only_node";
1248            $this->setIsConfiguredSplashOnly(empty ($_REQUEST[$name]) ? false : true);
1249        }
1250
1251        // custom_portal_redirect_url
1252        if ($network->getCustomPortalRedirectAllowed())
1253        {
1254            $name = "node_".$node_id."_custom_portal_redirect_url";
1255            $this->setCustomPortalRedirectUrl($_REQUEST[$name]);
1256        }
1257
1258        // End Node configuration section
1259
1260        // Access rights
1261        Stakeholder::processAssignStakeholdersUI($this, $errMsg);
1262        if(!empty($errMsg)) {
1263            echo $errMsg;
1264        }
1265    }
1266
1267    // Redirect to this node's portal page
1268    public function getUserUI()
1269    {
1270        header("Location: ".BASE_SSL_PATH."portal/?node_id=".$this->getId());
1271    }
1272
1273    /** Add content to this node */
1274    public function addContent(Content $content)
1275    {
1276        $db = AbstractDb::getObject();
1277        $content_id = $db->escapeString($content->getId());
1278        $sql = "INSERT INTO node_has_content (node_id, content_id) VALUES ('$this->id','$content_id')";
1279        $db->execSqlUpdate($sql, false);
1280        exit;
1281    }
1282
1283    /** Remove content from this node */
1284    public function removeContent(Content $content)
1285    {
1286        $db = AbstractDb::getObject();
1287        $content_id = $db->escapeString($content->getId());
1288        $sql = "DELETE FROM node_has_content WHERE node_id='$this->id' AND content_id='$content_id'";
1289        $db->execSqlUpdate($sql, false);
1290    }
1291
1292    /**
1293     * The list of the 5 most recent users who have logged into this node in the past week
1294     *
1295     * @return array An array of User object, or an empty array
1296     *
1297     * @access public
1298     */
1299    public function getRecentUsers()
1300    {
1301         
1302        $db = AbstractDb::getObject();
1303
1304        // Init values
1305        $retval = array();
1306        $users = null;
1307        $anonUsers = 0;
1308        $weekAgoDate = strftime("%Y-%m-%d 00:00", strtotime("-1 week"));
1309
1310        $db->execSql("SELECT DISTINCT users.user_id FROM users,connections WHERE connections.timestamp_in>'{$weekAgoDate}' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}' LIMIT 5", $users, false);
1311
1312        if ($users != null) {
1313            foreach ($users as $user_row) {
1314                $retval[] = User::getObject($user_row['user_id']);
1315            }
1316        }
1317
1318        return $retval;
1319    }
1320
1321    /**
1322     * The list of the 5 users who have logged into this node most often
1323     *
1324     * @return array An array of User object, or an empty array
1325     *
1326     * @access public
1327     */
1328    public function getActiveUsers()
1329    {
1330         
1331        $db = AbstractDb::getObject();
1332
1333        // Init values
1334        $retval = array();
1335        $users = null;
1336        $anonUsers = 0;
1337
1338        $db->execSql("SELECT DISTINCT users.user_id, count(users.user_id) as connections FROM users, connections WHERE users.user_id=connections.user_id AND connections.node_id='{$this->id}' GROUP BY users.user_id ORDER BY connections desc LIMIT 5", $users, false);
1339
1340        if ($users != null) {
1341            foreach ($users as $user_row) {
1342                $retval[] = User::getObject($user_row['user_id']);
1343            }
1344        }
1345
1346        return $retval;
1347    }
1348
1349    /**
1350     * The list of users online at this node
1351     *
1352     * @return array An array of User object, or an empty array
1353     *
1354     * @access public
1355     */
1356    public function getOnlineUsers()
1357    {
1358         
1359        $db = AbstractDb::getObject();
1360
1361        // Init values
1362        $retval = array();
1363        $users = null;
1364        $anonUsers = 0;
1365
1366        $db->execSql("SELECT users.user_id FROM users,connections WHERE connections.token_status='".TOKEN_INUSE."' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}'", $users, false);
1367
1368        if ($users != null) {
1369            foreach ($users as $user_row) {
1370                $retval[] = User::getObject($user_row['user_id']);
1371            }
1372        }
1373
1374        return $retval;
1375    }
1376
1377    /**
1378     * Find out how many users are online this specific Node
1379     *
1380     * @return int Number of online users
1381     *
1382     * @access public
1383     */
1384    public function getNumOnlineUsers()
1385    {
1386         
1387        $db = AbstractDb::getObject();
1388
1389        // Init values
1390        $retval = array ();
1391        $row = null;
1392
1393        if (!$this->isConfiguredSplashOnly()) {
1394            $db->execSqlUniqueRes("SELECT COUNT(DISTINCT users.user_id) as count FROM users,connections WHERE connections.token_status='".TOKEN_INUSE."' AND users.user_id=connections.user_id AND connections.node_id='{$this->id}'", $row, false);
1395        } else {
1396            $db->execSqlUniqueRes("SELECT COUNT(DISTINCT connections.user_mac) as count FROM connections WHERE connections.token_status='".TOKEN_INUSE."' AND connections.node_id='{$this->id}'", $row, false);
1397        }
1398
1399        return $row['count'];
1400    }
1401
1402    /** The list of all Technical officers of this node.
1403     * Technical officers are displayed highlited and in the online user's list,
1404     * and are contacted when the Node goes down.
1405     * @return An array of User object, or en empty array */
1406    function DEPRECATEDgetTechnicalOfficers()
1407    {
1408        $db = AbstractDb::getObject();
1409        $retval = array ();
1410        $officers = null;
1411        $db->execSql("SELECT user_id FROM node_stakeholders WHERE role_id = 'IS_TECH_OFFICER' AND object_id='{$this->id}'", $officers, false);
1412        if ($officers != null)
1413        {
1414            foreach ($officers as $officer_row)
1415            {
1416                $retval[] = User :: getObject($officer_row['user_id']);
1417            }
1418        }
1419        return $retval;
1420    }
1421
1422    /** Reloads the object from the database.  Should normally be called after a set operation */
1423    protected function refresh()
1424    {
1425        $this->__construct($this->id);
1426    }
1427    /** Menu hook function */
1428    static public function hookMenu() {
1429        $items = array();
1430        if(Security::getObjectsWithPermission(Permission::P('NETWORK_PERM_EDIT_ANY_NODE_CONFIG')))
1431        {
1432            $items[] = array('path' => 'node/node_edit',
1433            'title' => _("Edit nodes"),
1434            'url' => BASE_URL_PATH."admin/generic_object_admin.php?object_class=Node&action=list"
1435                );
1436        }
1437        else if($nodes = Security::getObjectsWithPermission(Permission::P('NODE_PERM_EDIT_CONFIG'))) {
1438             
1439            foreach ($nodes as $nodeId => $node) {
1440                $items[] = array('path' => 'node/node_'.$nodeId.'edit',
1441                'title' => sprintf(_("Edit %s"), $node->getName()),
1442                'url' => BASE_URL_PATH."admin/generic_object_admin.php?object_class=Node&action=edit&object_id=$nodeId"
1443                );
1444            }
1445        }
1446        $items[] = array('path' => 'node',
1447        'title' => _('Node administration'),
1448        'type' => MENU_ITEM_GROUPING);
1449        return $items;
1450    }
1451    /**
1452     * Assigns values about node to be processed by the Smarty engine.
1453     *
1454     * @param object $smarty Smarty object
1455     * @param object $node    Node object, if unset, the current node will be used
1456     *
1457     * @return void
1458     */
1459    public static function assignSmartyValues($smarty, $node = null)
1460    {
1461        if (!$node) {
1462            $node = self::getCurrentNode();
1463        }
1464
1465        // Set node details
1466        $smarty->assign('nodeId', $node ? $node->getId() : '');
1467        $smarty->assign('nodeName', $node ? $node->getName() : '');
1468        $smarty->assign('nodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1469        $smarty->assign('nodeNumOnlineUsers', $node ? $node->getNumOnlineUsers() : '');
1470        $smarty->assign('nodeWebSiteURL', $node ? $node->getWebSiteURL() : '');
1471        $node = self::getCurrentRealNode();
1472        // Set node details
1473        $smarty->assign('realNodeId', $node ? $node->getId() : '');
1474        $smarty->assign('realNodeName', $node ? $node->getName() : '');
1475        $smarty->assign('realNodeLastHeartbeatIP', $node ? $node->getLastHeartbeatIP() : '');
1476    }
1477}
1478
1479/*
1480 * Local variables:
1481 * tab-width: 4
1482 * c-basic-offset: 4
1483 * c-hanging-comment-ender-p: nil
1484 * End:
1485 */
Note: See TracBrowser for help on using the browser.