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

Revision 1090, 24.4 KB (checked in by benoitg, 7 years ago)

filter content type according to various criteria. Will be used more
extensively in the profile manager.

  • Content manager: Use content type filter to only allow Simple

content types (Content without metadata) to be used for metadata.

banner adds, or any other image rotation. Size constraints not yet
implemented

  • Move externally maintained class.phpmailer.php, class.smtp.php

into lib where they belong

  • DateTime?.php: Make class handle an empty date sensibly.
  • Network.php: Show the network again when there is only one.

It was confusing in some screens.

  • page.php: Clarify error message, and set a more reasonnable

paging cascade:

5 min, 30 min, 2 hours, 1 day, 1 week, 1 month

  • Finally fix #127
  • At last, working content scheduled display and expiration for

ContentGroups?. Archiving does not yet have a UI. Content that expires
will simply seem to disapear.

  • Fix #247 (somebody filed a bug before I commited, conveniently

saving me the need to describe it).

  • The Fix for #106 in [1089] returned non-objects, causing error

messages and not displaying what it was meant to display.

Used Guest instead of Annonymous, which will probably be

used for different purpose in the future.

This re-fix does not include duplicate counting yet.

Splash users are not the only users that could log-in multiple times.

I don't have a staging server here, a fix will be

commited in a few minutes if something goes wrong.

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