root/trunk/wifidog-auth/wifidog/classes/Content/ContentGroup/ContentGroupElement.php @ 1091

Revision 1091, 21.8 KB (checked in by benoitg, 7 years ago)

* Remove most inclusions of MainUI in classes. That completely
broke authentication (circular dependencies). Fixes 245.

Unfixes 242. Exceptions should not be caught in the context

they are thrown in. Else there no point in throwing exception in the
first place.
* HyperLink?.php: Fix bug where a link with identical text as
it's link would see the text replaced by the clickthrough-tracked
equivalent.

  • 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
4/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
5
6// +-------------------------------------------------------------------+
7// | WiFiDog Authentication Server                                     |
8// | =============================                                     |
9// |                                                                   |
10// | The WiFiDog Authentication Server is part of the WiFiDog captive  |
11// | portal suite.                                                     |
12// +-------------------------------------------------------------------+
13// | PHP version 5 required.                                           |
14// +-------------------------------------------------------------------+
15// | Homepage:     http://www.wifidog.org/                             |
16// | Source Forge: http://sourceforge.net/projects/wifidog/            |
17// +-------------------------------------------------------------------+
18// | This program is free software; you can redistribute it and/or     |
19// | modify it under the terms of the GNU General Public License as    |
20// | published by the Free Software Foundation; either version 2 of    |
21// | the License, or (at your option) any later version.               |
22// |                                                                   |
23// | This program is distributed in the hope that it will be useful,   |
24// | but WITHOUT ANY WARRANTY; without even the implied warranty of    |
25// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     |
26// | GNU General Public License for more details.                      |
27// |                                                                   |
28// | You should have received a copy of the GNU General Public License |
29// | along with this program; if not, contact:                         |
30// |                                                                   |
31// | Free Software Foundation           Voice:  +1-617-542-5942        |
32// | 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        |
33// | Boston, MA  02111-1307,  USA       gnu@gnu.org                    |
34// |                                                                   |
35// +-------------------------------------------------------------------+
36
37/**
38 * This file isn't in Content because it must only be instanciated as part of a
39 * ContentGroup
40 *
41 * @package    WiFiDogAuthServer
42 * @subpackage ContentClasses
43 * @author     Benoit Grégoire <bock@step.polymtl.ca>
44 * @copyright  2005-2006 Benoit Grégoire, Technologies Coeus inc.
45 * @version    Subversion $Id$
46 * @link       http://www.wifidog.org/
47 */
48
49/**
50 * Load required classes
51 */
52require_once ('classes/Content/ContentGroup/ContentGroup.php');
53require_once ('classes/Node.php');
54
55/**
56 * The elements of a ContentGroup
57 *
58 * @package    WiFiDogAuthServer
59 * @subpackage ContentClasses
60 * @author     Benoit Grégoire <bock@step.polymtl.ca>
61 * @copyright  2005-2006 Benoit Grégoire, Technologies Coeus inc.
62 */
63class ContentGroupElement extends Content {
64
65        /**
66       
67         */
68        private $content_group_element_row;
69
70        /**
71         * Constructor
72         *
73         * @param string $content_id Content Id
74         *
75         * @return void     */
76        protected function __construct($content_id) {
77                // Define globals
78                global $db;
79
80                // Init values
81                $row = null;
82
83                parent :: __construct($content_id);
84                $content_id = $db->escapeString($content_id);
85
86                $sql_select = "SELECT * FROM content_group_element WHERE content_group_element_id='$content_id'";
87                $db->execSqlUniqueRes($sql_select, $row, false);
88
89                if ($row == null) {
90                        // The database was corrupted, let's fix it ...
91                        $sql = "DELETE FROM content WHERE content_id='$content_id'";
92                        $db->execSqlUpdate($sql, true);
93                }
94
95                $this->content_group_element_row = $row;
96
97                /* A content group element is NEVER persistent */
98                parent :: setIsPersistent(false);
99        }
100        /** When a content object is set as Simple, it means that is is used merely to contain it's own data.  No title, description or other metadata will be set or displayed, during display or administration
101         * @return true or false */
102        public function isSimpleContent() {
103                return true;
104        }
105        /**
106         * Replace and delete the old displayed_content (if any) by the new
107         * content (or no content)
108         *
109         * @param object $new_displayed_content Content object or null. If
110         *                                      null the old content is still
111         *                                      deleted.
112         *
113         * @return void
114       
115         */
116        private function replaceDisplayedContent($new_displayed_content) {
117                // Define globals
118                global $db;
119
120                // Init values
121                $old_displayed_content = null;
122                $errmsg = null;
123
124                if (!empty ($this->content_group_element_row['displayed_content_id'])) {
125                        $old_displayed_content = self :: getObject($this->content_group_element_row['displayed_content_id']);
126                }
127
128                if ($new_displayed_content != null) {
129                        $new_displayed_content_id_sql = "'" . $new_displayed_content->GetId() . "'";
130                } else {
131                        $new_displayed_content_id_sql = "NULL";
132                }
133
134                $db->execSqlUpdate("UPDATE content_group_element SET displayed_content_id = $new_displayed_content_id_sql WHERE content_group_element_id = '$this->id'", FALSE);
135
136                if ($old_displayed_content != null) {
137                        $old_displayed_conten->delete($errmsg);
138                }
139        }
140
141        /**
142         * Get the order of the element in the content group
143         *
144         * @return string the order of the element in the content group
145         */
146        public function getDisplayOrder() {
147                return $this->content_group_element_row['display_order'];
148        }
149
150        /**
151         * Set the order of the element in the content group
152         *
153         * @param string $order Order how items should be displayed
154         *
155         * @return void
156         */
157        public function setDisplayOrder($order) {
158                // Define globals
159                global $db;
160
161                if ($order != $this->getDisplayOrder()) {
162                        /*
163                         * Only update database if there is an actual change
164                         */
165                        $order = $db->escapeString($order);
166                        $db->execSqlUpdate("UPDATE content_group_element SET display_order = $order WHERE content_group_element_id = '$this->id'", false);
167                }
168        }
169
170        /**
171         * Like the same method as defined in Content, this method will create a
172         * ContentGroupElement based on the content type specified by
173         * getNewContentUI OR get an existing element by getSelectExistingContentUI
174         *
175         * @param string $user_prefix                A identifier provided by the programmer to
176         *                                           recognise it's generated form
177         * @param string $content_group              Must be present
178         * @param bool   $associate_existing_content If set to true, will get an
179         *                                           existing element instead of creating a
180         *                                           new content.
181         *
182         * @return object The ContentGroup object, or null if the user didn't greate one
183         * @static
184         */
185        public static function processNewContentUI($user_prefix, ContentGroup $content_group, $associate_existing_content = false) {
186                // Define globals
187                global $db;
188
189                // Init values
190                $content_group_element_object = null;
191                $max_display_order_row = null;
192
193                if ($associate_existing_content == true) {
194                        $name = "{$user_prefix}_add";
195                } else {
196                        $name = "get_new_content_{$user_prefix}_add";
197                }
198
199                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) {
200                        /* Get the display order to add the GontentGroupElement at the end */
201                        $sql = "SELECT MAX(display_order) as max_display_order FROM content_group_element WHERE content_group_id='" . $content_group->getId() . "'";
202                        $db->execSqlUniqueRes($sql, $max_display_order_row, false);
203                        $display_order = $max_display_order_row['max_display_order'] + 1;
204
205                        if ($associate_existing_content == true) {
206                                $name = "{$user_prefix}";
207                        } else {
208                                $name = "get_new_content_{$user_prefix}_content_type";
209                        }
210
211                        $content_id = get_guid();
212                        $content_type = 'ContentGroupElement';
213                        $sql = "INSERT INTO content (content_id, content_type) VALUES ('$content_id', '$content_type');";
214
215                        if (!$db->execSqlUpdate($sql, false)) {
216                                throw new Exception(_('Unable to insert new content into database!'));
217                        }
218
219                        $sql = "INSERT INTO content_group_element (content_group_element_id, content_group_id, display_order) VALUES ('$content_id', '" . $content_group->GetId() . "', $display_order);";
220
221                        if (!$db->execSqlUpdate($sql, false)) {
222                                throw new Exception(_('Unable to insert new content into database!'));
223                        }
224
225                        $content_group_element_object = self :: getObject($content_id);
226
227                        $content_ui_result = FormSelectGenerator :: getResult($name, null);
228
229                        if ($associate_existing_content == true) {
230                                $displayed_content_object = self :: getObject($content_ui_result);
231                        } else {
232                                $displayed_content_object = self :: createNewObject($content_ui_result);
233                        }
234
235                        $content_group_element_object->replaceDisplayedContent($displayed_content_object);
236                }
237
238                return $content_group_element_object;
239        }
240        /** If set, content will only be displayed from this date on. */
241        function getValidFromDate() {
242                return $this->content_group_element_row['valid_from_timestamp'];
243        }
244
245        /** If set, content will only be displayed from this date on.
246         * @param string @date Start date.  To always display, set to null or an empty string */
247        function setValidFromDate($date) {
248                // Define globals
249                global $db;
250                if ($date != $this->getValidFromDate()) {
251                        if (!empty ($date)) {
252                                $date = "'" . $db->escapeString($date) . "'";
253                        } else {
254                                $date = 'NULL';
255                        }
256                        $db->execSqlUpdate("UPDATE content_group_element SET valid_from_timestamp = {$date} WHERE content_group_element_id = '{$this->getId()}'");
257                        $this->refresh();
258                }
259        }
260        /** If set, content will only be displayed untill this date (and will then be archived). */
261        function getValidUntilDate() {
262                return $this->content_group_element_row['valid_until_timestamp'];
263        }
264
265        /** If set, content will only be displayed untill this date (and will then be archived).
266         * @param string @date End date.  To always display, set to null or an empty string */
267        function setValidUntilDate($date) {
268                // Define globals
269                global $db;
270                if ($date != $this->getValidUntilDate()) {
271                        if (!empty ($date)) {
272                                $date = "'" . $db->escapeString($date) . "'";
273                        } else {
274                                $date = 'NULL';
275                        }
276                        $db->execSqlUpdate("UPDATE content_group_element SET valid_until_timestamp = {$date} WHERE content_group_element_id = '{$this->getId()}'");
277                        $this->refresh();
278                }
279        }
280
281        /**
282         * Shows the administration interface for ContentGroupElement
283         *
284         * @param string $subclass_admin_interface HTML code to be added after the
285         *                                         administration interface
286         *
287         * @return string HTML code for the administration interface
288         */
289        public function getAdminUI($subclass_admin_interface = null, $title = null) {
290                // Define globals
291                global $db;
292
293                // Init values
294                $html = '';
295                $html .= "<li class='admin_element_item_container'>\n";
296                $html .= "<fieldset class='admin_element_group'>\n";
297                $html .= "<legend>" . sprintf(_("%s %d display conditions"), get_class($this), $this->getDisplayOrder()) . "</legend>\n";
298
299                $allowed_node_rows = null;
300                $html .= "<ul class='admin_element_list'>\n";
301                /* display_order */
302                $html .= "<li class='admin_element_item_container'>\n";
303                $html .= "<div class='admin_element_label'>Display order: </div>\n";
304                $html .= "<div class='admin_element_data'>\n";
305                $name = "content_group_element_" . $this->id . "_display_order";
306                $html .= "<input type='text' name='$name' value='" . $this->getDisplayOrder() . "' size='2'>\n";
307                $html .= _("(Ignored if display type is random)") . "\n";
308                $html .= "</div>\n";
309                $html .= "</li>\n";
310
311                $html .= "<li class='admin_element_item_container'>\n";
312                // valid_from_timestamp
313                $html .= "<div class='admin_element_label'>" . _("Only display from") . "</div>\n";
314                $html .= "<div class='admin_element_data'>\n";
315                $name = "content_group_element_" . $this->id . "_valid_from";
316                $html .= DateTime :: getSelectDateTimeUI(new DateTime($this->getValidFromDate()), $name, DateTime :: INTERFACE_DATETIME_FIELD, null);
317                $html .= "</div>\n";
318
319                // valid_until_timestamp
320                $html .= "<div class='admin_element_label'>until</div>\n";
321                $html .= "<div class='admin_element_data'>\n";
322                $name = "content_group_element_" . $this->id . "_valid_until";
323                $html .= DateTime :: getSelectDateTimeUI(new DateTime($this->getValidUntilDate()), $name, DateTime :: INTERFACE_DATETIME_FIELD, null);
324                $html .= "</div>\n";
325
326                $html .= _("(Content can be displayed at any date if no start or end date is specified.  Warning:  If you do not specify a specifig time of day, midnight is assumed.)") . "\n";
327                $html .= "</li>\n";
328
329                /* content_group_element_has_allowed_nodes */
330                $html .= "<li class='admin_element_item_container'>\n";
331                $html .= "<div class='admin_element_label'>" . _("Only display at node(s):") . "</div>\n";
332                $html .= "<ul class='admin_element_list'>\n";
333
334                $sql = "SELECT * FROM content_group_element_has_allowed_nodes WHERE content_group_element_id='$this->id'";
335                $db->execSql($sql, $allowed_node_rows, false);
336
337                if ($allowed_node_rows != null) {
338                        foreach ($allowed_node_rows as $allowed_node_row) {
339                                $node = Node :: getObject($allowed_node_row['node_id']);
340                                $html .= "<li class='admin_element_item_container'>\n";
341                                $html .= "<div class='admin_element_data'>\n";
342                                $html .= "" . $node->GetId() . ": " . $node->GetName() . "";
343                                $html .= "</div>\n";
344                                $html .= "<div class='admin_element_tools'>\n";
345                                $name = "content_group_element_" . $this->id . "_allowed_node_" . $node->GetId() . "_remove";
346                                $html .= "<input type='submit' name='$name' value='" . _("Remove") . "'>";
347                                $html .= "</div>\n";
348                                $html .= "</li>\n";
349                        }
350                }
351
352                $html .= "<li class='admin_element_item_container'>\n";
353
354                $sql_additional_where = "AND node_id NOT IN (SELECT node_id FROM content_group_element_has_allowed_nodes WHERE content_group_element_id='$this->id')";
355                $name = "content_group_element_{$this->id}_new_allowed_node";
356                $html .= Node :: getSelectNodeUI($name, $sql_additional_where);
357                $name = "content_group_element_{$this->id}_new_allowed_node_submit";
358                $html .= "<input type='submit' name='$name' value='" . _("Add new allowed node") . "'>";
359                $html .= "</li'>\n";
360                $html .= "</ul>\n";
361                $html .= _("(Content can be displayed at ANY node unless one or more nodes are selected)") . "\n";
362
363                $html .= "</li>\n";
364                $html .= "</fieldset>\n";
365                $html .= "</li>\n";
366
367                /* displayed_content_id */
368                $html .= "<li class='admin_element_item_container'>\n";
369                if (empty ($this->content_group_element_row['displayed_content_id'])) {
370                        $html .= "<div class='errormsg'>Sorry, display element is missing.</div>\n";
371                        /*              $html .= "<fieldset class='admin_element_group'>\n";
372                                                $html .= "<legend>"._("Add a new displayed content OR select an existing one")."</legend>\n";
373                                    $html .= self :: getNewContentUI("content_group_element_{$this->id}_new_displayed_content")."<br>";
374                                    $html .= self :: getSelectExistingContentUI("content_group_element_{$this->id}_new_displayed_existing_element", "AND content_id != '$this->id'");
375                                                $html .= "</fieldset>\n";*/
376                } else {
377                        $displayed_content = self :: getObject($this->content_group_element_row['displayed_content_id']);
378                        $html .= $displayed_content->getAdminUI(null, sprintf(_("%s %d displayed content (%s)"), get_class($this), $this->getDisplayOrder(), get_class($displayed_content)));
379                        /*$html .= "<div class='admin_element_tools'>\n";
380                        $name = "content_group_element_{$this->id}_erase_displayed_content";
381                        $html .= "<input type='submit' name='$name' value='"._("Delete")."'>";
382                        $html .= "</div>\n";*/
383                }
384                $html .= "</li>\n";
385
386                $html .= $subclass_admin_interface;
387
388                return parent :: getAdminUI($html, $title);
389        }
390
391        /**
392         * Processes the input of the administration interface for ContentGroupElement
393         *
394         * @return void
395         */
396        public function processAdminUI() {
397                // Define globals
398                global $db;
399
400                // Init values
401                $allowed_node_rows = null;
402                $errmsg = null;
403
404                parent :: processAdminUI();
405
406                /* display_order */
407                $name = "content_group_element_" . $this->id . "_display_order";
408                $this->setDisplayOrder($_REQUEST[$name]);
409
410                // valid_from_timestamp
411                $name = "content_group_element_" . $this->id . "_valid_from";
412                $this->setValidFromDate(DateTime :: processSelectDateTimeUI($name, DateTime :: INTERFACE_DATETIME_FIELD)->getIso8601FormattedString());
413
414                // valid_until_timestamp
415
416                $name = "content_group_element_" . $this->id . "_valid_until";
417                $this->setValidUntilDate(DateTime :: processSelectDateTimeUI($name, DateTime :: INTERFACE_DATETIME_FIELD)->getIso8601FormattedString());
418
419                /* content_group_element_has_allowed_nodes */
420                $sql = "SELECT * FROM content_group_element_has_allowed_nodes WHERE content_group_element_id='$this->id'";
421                $db->execSql($sql, $allowed_node_rows, false);
422
423                if ($allowed_node_rows != null) {
424                        foreach ($allowed_node_rows as $allowed_node_row) {
425                                $node = Node :: getObject($allowed_node_row['node_id']);
426                                $name = "content_group_element_" . $this->id . "_allowed_node_" . $node->GetId() . "_remove";
427
428                                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) {
429                                        $sql = "DELETE FROM content_group_element_has_allowed_nodes WHERE content_group_element_id='$this->id' AND node_id='" . $node->GetId() . "'";
430                                        $db->execSqlUpdate($sql, false);
431                                }
432                        }
433                }
434
435                $name = "content_group_element_{$this->id}_new_allowed_node_submit";
436
437                if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) {
438                        $name = "content_group_element_{$this->id}_new_allowed_node";
439                        $node = Node :: processSelectNodeUI($name);
440                        $node_id = $node->GetId();
441                        $db->execSqlUpdate("INSERT INTO content_group_element_has_allowed_nodes (content_group_element_id, node_id) VALUES ('$this->id', '$node_id')", FALSE);
442                }
443
444                /* displayed_content_id */
445                if (empty ($this->content_group_element_row['displayed_content_id'])) {
446                        // Could be either a new content or existing content ( try both successively )
447                        $displayed_content = Content :: processNewContentUI("content_group_element_{$this->id}_new_displayed_content");
448
449                        if ($displayed_content == null) {
450                                $displayed_content = Content :: processNewContentUI("content_group_element_{$this->id}_new_displayed_existing_element", true);
451                        }
452
453                        if ($displayed_content != null) {
454                                $displayed_content_id = $displayed_content->GetId();
455                                $db->execSqlUpdate("UPDATE content_group_element SET displayed_content_id = '$displayed_content_id' WHERE content_group_element_id = '$this->id'", FALSE);
456                                $displayed_content->setIsPersistent(false);
457                        }
458                } else {
459                        $displayed_content = self :: getObject($this->content_group_element_row['displayed_content_id']);
460                        $name = "content_group_element_{$this->id}_erase_displayed_content";
461
462                        if (!empty ($_REQUEST[$name]) && $_REQUEST[$name] == true) {
463                                if ($displayed_content->delete($errmsg) != false) {
464                                        $db->execSqlUpdate("UPDATE content_group_element SET displayed_content_id = NULL WHERE content_group_element_id = '$this->id'", FALSE);
465                                } else {
466                                        echo $errmsg;
467                                }
468                        } else {
469                                $displayed_content->processAdminUI();
470                        }
471                }
472        }
473
474        /**
475         * Retreives the user interface of this object.
476         *
477         * @return string The HTML fragment for this interface
478         */
479        public function getUserUI($subclass_user_interface = null) {
480                // Init values
481                $html = '';
482
483                if (!empty ($this->content_group_element_row['displayed_content_id'])) {
484                        $displayed_content = self :: getObject($this->content_group_element_row['displayed_content_id']);
485
486                        // If the content group logging is disabled, all the children will inherit this property temporarly
487                        if ($this->getLoggingStatus() == false) {
488                                $displayed_content->setLoggingStatus(false);
489                        }
490
491                        $displayed_content_html = $displayed_content->getUserUI();
492                }
493
494                $html .= "<div class='user_ui_container " . get_class($this) . "'>\n";
495                $html .= $displayed_content_html;
496                $html .= $subclass_user_interface;
497                $html .= "</div>\n";
498
499                return parent :: getUserUI($html);
500        }
501
502        /**
503         * Returns if this this Content element is displayable at this hotspot
504         *
505         * @param string $node Node Id
506         *
507         * @return bool True if it is displayable
508         */
509        public function isDisplayableAt($node) {
510                // Define globals
511                global $db;
512
513                // Init values
514                $retval = false;
515                $allowed_node_rows = null;
516
517                $sql = "SELECT * FROM content_group_element_has_allowed_nodes WHERE content_group_element_id='$this->id'";
518                $db->execSql($sql, $allowed_node_rows, false);
519
520                if ($allowed_node_rows != null) {
521                        if ($node) {
522                                $node_id = $node->getId();
523                                /**
524                                 * @todo  Proper algorithm, this is a dirty and slow hack
525                                 */
526                                foreach ($allowed_node_rows as $allowed_node_row) {
527                                        if ($allowed_node_row['node_id'] == $node_id) {
528                                                $retval = true;
529                                        }
530                                }
531                        } else {
532                                /* There are allowed nodes, but we don't know at which node we want to display */
533                                $retval = false;
534                        }
535                } else {
536                        /* No allowed node means all nodes are allowed */
537                        $retval = true;
538                }
539
540                return $retval;
541        }
542
543        /**
544         * Detects if a user is owner of a ContentGroupElement
545         *
546         * Override the method in Content.
547         *
548         * The owners of the content element are always considered to be the ContentGroup's
549         *
550         * @param object $user User object: the user to be tested.
551         *
552         * @return bool True if the user is a owner, false if he isn't or if the user is null
553         */
554        public function isOwner($user) {
555                $content_group = Content :: getObject($this->content_group_element_row['content_group_id']);
556                return $content_group->isOwner($user);
557        }
558
559        /**
560         * Deletes a ContentGroupElement object
561         *
562         * @param string $errmsg Reference to error message
563         *
564         * @return bool True if deletion was successful
565         * @internal Persistent content will not be deleted
566         *
567         * @todo Implement proper access control
568         */
569        public function delete(& $errmsg) {
570                if ($this->isPersistent() == false && !empty ($this->content_group_element_row['displayed_content_id'])) {
571                        $displayed_content = self :: getObject($this->content_group_element_row['displayed_content_id']);
572                        $displayed_content->delete($errmsg);
573                        parent :: delete($errmsg);
574                }
575        }
576        /** Reloads the object from the database.  Should normally be called after a set operation */
577        protected function refresh() {
578                $this->__construct($this->id);
579        }
580}
581
582/*
583 * Local variables:
584 * tab-width: 4
585 * c-basic-offset: 4
586 * c-hanging-comment-ender-p: nil
587 * End:
588 */
Note: See TracBrowser for help on using the browser.