Source for file forumfunction.inc.php
Documentation is available at forumfunction.inc.php
==============================================================================
Dokeos - elearning and course management software
Copyright (c) 2006-2008 Dokeos SPRL
Copyright (c) 2006 Ghent University (UGent)
For a full list of contributors, see "credits.txt".
The full license can be read in "license.txt".
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
See the GNU General Public License for more details.
Contact address: Dokeos, rue du Corbeau, 108, B-1030 Brussels, Belgium
==============================================================================
* These files are a complete rework of the forum. The database structure is
* based on phpBB but all the code is rewritten. A lot of new functionalities
* - forum categories and forums can be sorted up or down, locked or made invisible
* - consistent and integrated forum administration
* - forum options: are students allowed to edit their post?
* moderation of posts (approval)
* reply only forums (students cannot create new threads)
* multiple forums per group
* - new view option: nested view
* @Author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @Copyright Ghent University
* @Copyright Patrick Cool
* @todo several functions have to be moved to the itemmanager library
* @todo displaying icons => display library
* @todo complete the missing phpdoc the correct order should be
* some explanation of the function
* @author firstname lastname <email>, organisation
* @version (day) month year
*************************************************************************
* Please do not change anything is this code yet because there are still
* some significant code that need to happen and I do not have the time to
* merge files and test it all over again. So for the moment, please do not
* -- Patrick Cool <patrick.cool@UGent.be>
*************************************************************************
require_once(api_get_path(INCLUDE_PATH). '/lib/mail.lib.inc.php');
require_once(api_get_path(INCLUDE_PATH). '/conf/mail.conf.php');
require_once(api_get_path(INCLUDE_PATH). '/lib/usermanager.lib.php');
* This function handles all the forum and forumcategories actions. This is a wrapper for the
* forum and forum categories. All this code code could go into the section where this function is
* called but this make the code there cleaner.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// Adding a forum category
if (($_GET['action']== 'add' AND $_GET['content']== 'forumcategory') OR $_POST['SubmitForumCategory'] )
if ((($_GET['action']== 'add' OR $_GET['action']== 'edit') AND $_GET['content']== 'forum') OR $_POST['SubmitForum'] )
if ($_GET['action']== 'edit' and isset ($_GET['id']) OR $_POST['SubmitForum'] )
if (($_GET['action']== 'edit' AND $_GET['content']== 'forumcategory' AND isset ($_GET['id'])) OR $_POST['SubmitEditForumCategory'] )
// Delete a forum category
if ($_GET['action']== 'delete' AND isset ($_GET['content']) AND isset ($_GET['id']))
// Change visibility of a forum or a forum category
if (($_GET['action']== 'invisible' OR $_GET['action']== 'visible') AND isset ($_GET['content']) AND isset ($_GET['id']))
$return_message= change_visibility($_GET['content'], $_GET['id'],$_GET['action']);// note: this has to be cleaned first
// Change lock status of a forum or a forum category
if (($_GET['action']== 'lock' OR $_GET['action']== 'unlock') AND isset ($_GET['content']) AND isset ($_GET['id']))
$return_message= change_lock_status($_GET['content'], $_GET['id'],$_GET['action']);// note: this has to be cleaned first
// Move a forum or a forum category
if ($_GET['action']== 'move' AND isset ($_GET['content']) AND isset ($_GET['id']) AND isset ($_GET['direction']))
$return_message= move_up_down($_GET['content'], $_GET['direction'], $_GET['id']);// note: this has to be cleaned first
* This function displays the form that is used to add a forum category.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// settting the form elements
$form->addElement('header', '', get_lang('AddForumCategory'));
$form->addElement('text', 'forum_category_title', get_lang('Title'),'class="input_titles"');
$form->addElement('html_editor', 'forum_category_comment', get_lang('Comment'));
$form->addElement('submit', 'SubmitForumCategory', 'OK');
$form->addRule('forum_category_title', '<div class="required">'. get_lang('ThisFieldIsRequired'), 'required');
// The validation or display
$values = $form->exportValues();
* This function displays the form that is used to add a forum category.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// the header for the form
$session_header = isset ($_SESSION['session_name']) ? ' ('. $_SESSION['session_name']. ') ' : '';
$form->addElement('header', '', get_lang('AddForum'). $session_header);
// we have a hidden field if we are editing
$form->addElement('hidden', 'forum_id', $inputvalues['forum_id']);
// The title of the forum
$form->addElement('text', 'forum_title', get_lang('Title'),'class="input_titles"');
// The comment of the forum
$form->addElement('html_editor', 'forum_comment', get_lang('Comment'));
// dropdown list: Forum Categories
foreach ($forum_categories as $key=> $value)
$forum_categories_titles[$value['cat_id']]= $value['cat_title'];
$form->addElement('select', 'forum_category', get_lang('InForumCategory'), $forum_categories_titles);
//$form->addElement('radio', 'allow_anonymous', get_lang('AllowAnonymousPosts'), get_lang('Yes'), 1);
//$form->addElement('radio', 'allow_anonymous', '', get_lang('No'), 0);
// This is for horizontal
$form->addGroup($group, 'allow_anonymous_group', get_lang('AllowAnonymousPosts'), ' ');
//$form->addElement('radio', 'students_can_edit', get_lang('StudentsCanEdit'), get_lang('Yes'), 1);
//$form->addElement('radio', 'students_can_edit', '', get_lang('No'), 0);
// This is for horizontal
$form->addGroup($group, 'students_can_edit_group', get_lang('StudentsCanEdit'), ' ');
//$form->addElement('radio', 'approval_direct', get_lang('ApprovalDirect'), get_lang('Approval'), 1);
//$form->addElement('radio', 'approval_direct', '', get_lang('Direct'), 0);
// This is for horizontal
//$form->addGroup($group, 'approval_direct_group', get_lang('ApprovalDirect'), ' ');
//$form->addElement('radio', 'allow_attachments', get_lang('AllowAttachments'), get_lang('Yes'), 1);
//$form->addElement('radio', 'allow_attachments', '', get_lang('No'), 0);
// This is for horizontal
//$form->addGroup($group, 'allow_attachments_group', get_lang('AllowAttachments'), ' ');
//$form->addElement('radio', 'allow_new_threads', get_lang('AllowNewThreads'), 1, get_lang('Yes'));
//$form->addElement('radio', 'allow_new_threads', '', 0, get_lang('No'));
// This is for horizontal
$form->addGroup($group, 'allow_new_threads_group', get_lang('AllowNewThreads'), ' ');
$form->addGroup($group, 'default_view_type_group', get_lang('DefaultViewType'), ' ');
$form->addElement('static','Group', '<br /><strong>'. get_lang('GroupSettings'). '</strong>');
$groups_titles[0]= get_lang('NotAGroupForum');
foreach ($groups as $key=> $value)
$groups_titles[$value['id']]= $value['name'];
$form->addElement('select', 'group_forum', get_lang('ForGroup'), $groups_titles);
// Public or private group forum
$form->addGroup($group, 'public_private_group_forum_group', get_lang('PublicPrivateGroupForum'), ' ');
$form->addElement('submit', 'SubmitForum', 'OK');
$form->addRule('forum_title', get_lang('ThisFieldIsRequired'), 'required');
$form->addRule('forum_category', get_lang('ThisFieldIsRequired'), 'required');
$defaults['allow_anonymous_group']['allow_anonymous']= 0;
$defaults['students_can_edit_group']['students_can_edit']= 0;
$defaults['approval_direct_group']['approval_direct']= 0;
$defaults['allow_attachments_group']['allow_attachments']= 1;
$defaults['allow_new_threads_group']['allow_new_threads']= 1;
$defaults['default_view_type_group']['default_view_type']= api_get_setting('default_forum_view');
$defaults['public_private_group_forum_group']['public_private_group_forum']= 'public';
if (isset ($_GET['forumcategory']))
$defaults['forum_category']= $_GET['forumcategory'];
else // the default values when editing = the data in the table
$defaults['forum_id']= $inputvalues['forum_id'];
$defaults['forum_category']= $inputvalues['forum_category'];
$defaults['allow_anonymous_group']['allow_anonymous']= $inputvalues['allow_anonymous'];
$defaults['students_can_edit_group']['students_can_edit']= $inputvalues['allow_edit'];
$defaults['approval_direct_group']['approval_direct']= $inputvalues['approval_direct_post'];
$defaults['allow_attachments_group']['allow_attachments']= $inputvalues['allow_attachments'];
$defaults['allow_new_threads_group']['allow_new_threads']= $inputvalues['allow_new_threads'];
$defaults['default_view_type_group']['default_view_type']= $inputvalues['default_view'];
$defaults['public_private_group_forum_group']['public_private_group_forum']= $inputvalues['forum_group_public_private'];
$defaults['group_forum']= $inputvalues['forum_of_group'];
$form->setDefaults($defaults);
// The validation or display
$values = $form->exportValues();
* This function displays the form that is used to edit a forum category.
* This is more or less a copy from the show_add_forumcategory_form function with the only difference that is uses
* some default values. I tried to have both in one function but this gave problems with the handle_forum_and_forumcategories function
* (storing was done twice)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// settting the form elements
$form->addElement('header', '', get_lang('EditForumCategory'));
$form->addElement('hidden', 'forum_category_id');
$form->addElement('text', 'forum_category_title', get_lang('Title'),'class="input_titles"');
$form->addElement('html_editor', 'forum_category_comment', get_lang('Comment'));
$form->addElement('submit', 'SubmitEditForumCategory', 'OK');
// setting the default values
$defaultvalues['forum_category_id']= $inputvalues['cat_id'];
$defaultvalues['forum_category_comment']= prepare4display($inputvalues['cat_comment']);
$form->setDefaults($defaultvalues);
$form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
// The validation or display
$values = $form->exportValues();
* This function stores the forum category in the database. The new category is added to the end.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_categories;
// find the max cat_order. The new forum category is added at the end => max cat_order + &
$new_max= $row['sort_max']+ 1;
if (isset ($values['forum_category_id']))
$sql= "UPDATE ". $table_categories. " SET cat_title='". $clean_cat_title. "', cat_comment='". Database::escape_string($values['forum_category_comment']). "' WHERE cat_id='". Database::escape_string($values['forum_category_id']). "'";
$return_message= get_lang('ForumCategoryEdited');
$sql= "INSERT INTO ". $table_categories. " (cat_title, cat_comment, cat_order) VALUES ('". $clean_cat_title. "','". Database::escape_string($values['forum_category_comment']). "','". Database::escape_string($new_max). "')";
$return_message= get_lang('ForumCategoryAdded');
* This function stores the forum in the database. The new forum is added to the end.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
$sql= "SELECT MAX(forum_order) as sort_max FROM ". $table_forums. " WHERE forum_category=". Database::escape_string($values['forum_category']);
$new_max= $row['sort_max']+ 1;
$session_id = isset ($_SESSION['id_session']) ? $_SESSION['id_session'] : 0;
if (isset ($values['forum_id']))
$sql= "UPDATE ". $table_forums. " SET
forum_title='". $clean_title. "',
allow_attachments='". Database::escape_string($values['allow_attachments_group']['allow_attachments']). "',
allow_new_threads='". Database::escape_string($values['allow_new_threads_group']['allow_new_threads']). "',
forum_group_public_private='". Database::escape_string($values['public_private_group_forum_group']['public_private_group_forum']). "',
$return_message= get_lang('ForumEdited');
$sql= "INSERT INTO ". $table_forums. "
(forum_title, forum_comment, forum_category, allow_anonymous, allow_edit, approval_direct_post, allow_attachments, allow_new_threads, default_view, forum_of_group, forum_group_public_private, forum_order, session_id)
VALUES ('". $clean_title. "',
'". Database::escape_string($values['public_private_group_forum_group']['public_private_group_forum']). "',
* This function deletes a forum or a forum category
* This function currently does not delete the forums inside the category, nor the threads and replies inside these forums.
* For the moment this is the easiest method and it has the advantage that it allows to recover fora that were acidently deleted
* when the forum category got deleted.
* @param $content = what we are deleting (a forum or a forum category)
* @param $id The id of the forum category that has to be deleted.
* @todo write the code for the cascading deletion of the forums inside a forum category and also the threads and replies inside these forums
* @todo config setting for recovery or not (see also the documents tool: real delete or not).
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
if ($content== 'forumcategory')
$return_message= get_lang('ForumCategoryDeleted');
$return_message= get_lang('ForumDeleted');
$return_message= get_lang('ThreadDeleted');
//delete_attachment($post_id);
* This function deletes a forum post. This separate function is needed because forum posts do not appear in the item_property table (yet)
* and because deleting a post also has consequence on the posts that have this post as parent_id (they are also deleted).
* an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
* We also have to decrease the number of replies in the thread table
* @param $post_id the id of the post that will be deleted
* @todo write recursive function that deletes all the posts that have this message as parent
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$sql= "DELETE FROM $table_posts WHERE post_id='". Database::escape_string($post_id). "'"; // note: this has to be a recursive function that deletes all of the posts in this block.
// Decreasing the number of replies for this thread and also changing the last post information
$sql= "UPDATE $table_threads SET thread_replies=thread_replies-1,
if ($last_post_of_thread== false)
// we deleted the very single post of the thread so we need to delete the entry in the thread table also.
return 'PostDeletedSpecial';
* This function gets the all information of the last (=most recent) post of the thread
* This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date
* @param $thread_id the id of the thread we want to know the last post of.
* @return an array if there is a last post found, false if there is no post entry linked to that thread => thread will be deleted
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$sql= "SELECT * FROM $table_posts WHERE thread_id='". Database::escape_string($thread_id). "' ORDER BY post_date DESC";
* This function takes care of the display of the visibility icon
* @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
* @param $id the id of the content we want to make invisible
* @param $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
if ($current_visibility_status== '1')
if (is_array($additional_url_parameters))
foreach ($additional_url_parameters as $key=> $value)
echo $key. '='. $value. '&';
echo 'action=invisible&content='. $content. '&id='. $id. '">'. icon('../img/visible.gif',get_lang('MakeInvisible')). '</a>';
if ($current_visibility_status== '0')
if (is_array($additional_url_parameters))
foreach ($additional_url_parameters as $key=> $value)
echo $key. '='. $value. '&';
echo 'action=visible&content='. $content. '&id='. $id. '">'. icon('../img/invisible.gif',get_lang('MakeVisible')). '</a>';
* This function takes care of the display of the lock icon
* @param $content what is it that we want to (un)lock: forum category, forum, thread, post
* @param $id the id of the content we want to (un)lock
* @param $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
if ($current_lock_status== '1')
if (is_array($additional_url_parameters))
foreach ($additional_url_parameters as $key=> $value)
echo $key. '='. $value. '&';
echo 'action=unlock&content='. $content. '&id='. $id. '">'. icon('../img/lock.gif',get_lang('Unlock')). '</a>';
if ($current_lock_status== '0')
if (is_array($additional_url_parameters))
foreach ($additional_url_parameters as $key=> $value)
echo $key. '='. $value. '&';
echo 'action=lock&content='. $content. '&id='. $id. '">'. icon('../img/unlock.gif',get_lang('Lock')). '</a>';
* This function takes care of the display of the up and down icon
* @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
* @param $id is the id of the item we want to display the icons for
* @param $list is an array of all the items. All items in this list should have an up and down icon except for the first (no up icon) and the last (no down icon)
* The key of this $list array is the id of the item.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$total_items= count($list);
foreach ($list as $key=> $listitem)
$position= $internal_counter;
$return_value= '<a href="'. api_get_self(). '?'. api_get_cidreq(). '&action=move&direction=up&content='. $content. '&id='. $id. '" title="'. get_lang('MoveUp'). '"><img src="../img/up.gif" /></a>';
$return_value= '<img src="../img/up_na.gif" />';
if ($position< $total_items)
$return_value.= '<a href="'. api_get_self(). '?'. api_get_cidreq(). '&action=move&direction=down&content='. $content. '&id='. $id. '" title="'. get_lang('MoveDown'). '" ><img src="../img/down.gif" /></a>';
$return_value.= '<img src="../img/down_na.gif" />';
* This function changes the visibility in the database (item_property)
* @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
* @param $id the id of the content we want to make invisible
* @param $target_visibility what is the current status of the visibility (0 = invisible, 1 = visible)
* @todo change the get parameter so that it matches the tool constants.
* @todo check if api_item_property_update returns true or false => returnmessage depends on it.
* @todo move to itemmanager
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
if ($target_visibility== 'visible')
* This function changes the lock status in the database
* @param $content what is it that we want to (un)lock: forum category, forum, thread, post
* @param $id the id of the content we want to (un)lock
* @param $action do we lock (=>locked value in db = 1) or unlock (=> locked value in db = 0)
* @return string, language variable
* @todo move to itemmanager
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_categories;
// Determine the relevant table
if ($content== 'forumcategory')
$table= $table_categories;
elseif ($content== 'forum')
elseif ($content== 'thread')
// Determine what we are doing => defines the value for the database and the return message
elseif ($action== 'unlock')
// Doing the change in the database
* This function moves a forum or a forum category up or down
* @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
* @param $direction do we want to move it up or down.
* @param $id the id of the content we want to make invisible
* @todo consider removing the table_item_property calls here but this can prevent unwanted side effects when a forum does not have an entry in
* the item_property table but does have one in the forum table.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_categories;
global $table_item_property;
// Determine which field holds the sort order
if ($content== 'forumcategory')
$table= $table_categories;
$sort_column= 'cat_order';
$sort_column= 'cat_order';
elseif ($content== 'forum')
$sort_column= 'forum_order';
$sort_column= 'forum_order';
// we also need the forum_category of this forum
$forum_category= $row['forum_category'];
// determine if need to sort ascending or descending
elseif ($direction== 'up')
if ($content== 'forumcategory')
$sql= "SELECT * FROM". $table_categories. " forum_categories, ". $table_item_property. " item_properties
WHERE forum_categories.cat_id=item_properties.ref
ORDER BY forum_categories.cat_order $sort_direction";
$sql= "SELECT * FROM". $table. " WHERE forum_category='". Database::escape_string($forum_category). "' ORDER BY forum_order $sort_direction";
// finding the items that need to be switched
//echo $row[$id_column].'-';
$next_id= $row[$id_column];
$next_sort= $row[$sort_column];
if($id== $row[$id_column])
$this_sort= $row[$sort_column];
// we do an extra check if we do not have illegal values. If your remove this if statment you will
// be able to mess with the sorting by refreshing the page over and over again.
if ($this_sort<> '' AND $next_sort<> '' AND $next_id<> '' AND $this_id<> '')
* This function returns a piece of html code that make the links grey (=invisible for the student)
* @param boolean 0/1: 0 = invisible, 1 = visible
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
if ($current_visibility_status== '0')
return "class='invisible'";
* Retrieve all the information off the forum categories (or one specific) for the current course.
* The categories are sorted according to their sorting order (cat_order
* @param $id default ''. When an id is passed we only find the information about that specific forum category. If no id is passed we get all the forum categories.
* @return an array containing all the information about all the forum categories
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$sql= "SELECT * FROM". $table_categories. " forum_categories, ". $table_item_property. " item_properties
WHERE forum_categories.cat_id=item_properties.ref
AND item_properties.visibility=1
ORDER BY forum_categories.cat_order ASC";
$sql= "SELECT * FROM". $table_categories. " forum_categories, ". $table_item_property. " item_properties
WHERE forum_categories.cat_id=item_properties.ref
AND item_properties.visibility<>2
ORDER BY forum_categories.cat_order ASC";
$sql= "SELECT * FROM". $table_categories. " forum_categories, ". $table_item_property. " item_properties
WHERE forum_categories.cat_id=item_properties.ref
ORDER BY forum_categories.cat_order ASC";
$forum_categories_list[$row['cat_id']]= $row;
$forum_categories_list= $row;
return $forum_categories_list;
* This function retrieves all the fora in a given forum category
* @param integer $cat_id the id of the forum category
* @return an array containing all the information about the forums (regardless of their category)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_item_property;
$sql= "SELECT * FROM ". $table_forums. " forum , ". $table_item_property. " item_properties
AND forum.forum_id=item_properties.ref
AND item_properties.visibility=1
ORDER BY forum.forum_order ASC";
$sql= "SELECT * FROM ". $table_forums. " forum , ". $table_item_property. " item_properties
AND forum.forum_id=item_properties.ref
AND item_properties.visibility<>2
ORDER BY forum_order ASC";
$forum_list[$row['forum_id']]= $row;
* Retrieve all the forums (regardless of their category) or of only one. The forums are sorted according to the forum_order.
* Since it does not take the forum category into account there probably will be two or more forums that have forum_order=1, ...
* @return an array containing all the information about the forums (regardless of their category)
* @todo check $sql4 because this one really looks fishy.
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_item_property;
// **************** GETTING ALL THE FORUMS ************************* //
$session_condition = isset ($_SESSION['id_session']) ? 'AND forum.session_id IN (0,'. intval($_SESSION['id_session']). ')' : '';
//-------------- Student -----------------//
// select all the forum information of all forums (that are visible to students)
$sql= "SELECT * FROM ". $table_forums. " forum , ". $table_item_property. " item_properties
WHERE forum.forum_id=item_properties.ref
AND item_properties.visibility=1
ORDER BY forum.forum_order ASC";
// select the number of threads of the forums (only the threads that are visible)
$sql2= "SELECT count(*) AS number_of_threads, threads.forum_id FROM $table_threads threads, ". $table_item_property. " item_properties
WHERE threads.thread_id=item_properties.ref
AND item_properties.visibility=1
GROUP BY threads.forum_id";
// select the number of posts of the forum (post that are visible and that are in a thread that is visible)
$sql3= "SELECT count(*) AS number_of_posts, posts.forum_id FROM $table_posts posts, $table_threads threads, ". $table_item_property. " item_properties
AND posts.thread_id=threads.thread_id
AND threads.thread_id=item_properties.ref
AND item_properties.visibility=1
GROUP BY threads.forum_id";
//-------------- Course Admin -----------------//
// select all the forum information of all forums (that are not deleted)
$sql= "SELECT * FROM ". $table_forums. " forum , ". $table_item_property. " item_properties
WHERE forum.forum_id=item_properties.ref
AND item_properties.visibility<>2
ORDER BY forum_order ASC";
// select the number of threads of the forums (only the threads that are not deleted)
$sql2= "SELECT count(*) AS number_of_threads, threads.forum_id FROM $table_threads threads, ". $table_item_property. " item_properties
WHERE threads.thread_id=item_properties.ref
AND item_properties.visibility<>2
GROUP BY threads.forum_id";
// select the number of posts of the forum
$sql3= "SELECT count(*) AS number_of_posts, forum_id FROM $table_posts GROUP BY forum_id";
// **************** GETTING ONE SPECIFIC FORUM ************************* //
// We could do the splitup into student and course admin also but we want to have as much as information about a certain forum as possible
// so we do not take too much information into account. This function (or this section of the function) is namely used to fill the forms
// when editing a forum (and for the moment it is the only place where we use this part of the function)
// select all the forum information of the given forum (that is not deleted)
$sql= "SELECT * FROM ". $table_forums. " forum , ". $table_item_property. " item_properties
WHERE forum.forum_id=item_properties.ref
AND item_properties.visibility<>2
ORDER BY forum_order ASC";
// select the number of threads of the forum
$sql2= "SELECT count(*) AS number_of_threads, forum_id FROM $table_threads WHERE forum_id=". Database::escape_string($id). " GROUP BY forum_id";
// select the number of posts of the forum
$sql3= "SELECT count(*) AS number_of_posts, forum_id FROM $table_posts WHERE forum_id=". Database::escape_string($id). " GROUP BY forum_id";
// select the last post and the poster (note: this is probably no longer needed)
$sql4= "SELECT post.post_id, post.forum_id, post.poster_id, post.poster_name, post.post_date, users.lastname, users.firstname
FROM $table_posts post, $table_users users
AND post.poster_id=users.user_id
ORDER BY post.post_id ASC";
// handling all the forum information
$forum_list[$row['forum_id']]= $row;
// handling the threadcount information
$forum_list[$row2['forum_id']]['number_of_threads']= $row2['number_of_threads'];
$forum_list['number_of_threads']= $row2['number_of_threads'];;
// handling the postcount information
if (array_key_exists($row3['forum_id'],$forum_list)) // this is needed because sql3 takes also the deleted forums into account
$forum_list[$row3['forum_id']]['number_of_posts']= $row3['number_of_posts'];
$forum_list['number_of_posts']= $row3['number_of_posts'];
// finding the last post information (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
foreach ($forum_list as $key=> $value)
$forum_list[$key]['last_post_id']= $last_post_info_of_forum['last_post_id'];
$forum_list[$key]['last_poster_id']= $last_post_info_of_forum['last_poster_id'];
$forum_list[$key]['last_post_date']= $last_post_info_of_forum['last_post_date'];
$forum_list[$key]['last_poster_name']= $last_post_info_of_forum['last_poster_name'];
$forum_list[$key]['last_poster_lastname']= $last_post_info_of_forum['last_poster_lastname'];
$forum_list[$key]['last_poster_firstname']= $last_post_info_of_forum['last_poster_firstname'];
$forum_list['last_post_id']= $last_post_info_of_forum['last_post_id'];
$forum_list['last_poster_id']= $last_post_info_of_forum['last_poster_id'];
$forum_list['last_post_date']= $last_post_info_of_forum['last_post_date'];
$forum_list['last_poster_name']= $last_post_info_of_forum['last_poster_name'];
$forum_list['last_poster_lastname']= $last_post_info_of_forum['last_poster_lastname'];
$forum_list['last_poster_firstname']= $last_post_info_of_forum['last_poster_firstname'];
* This functions gets all the last post information of a certain forum
* @param $forum_id the id of the forum we want to know the last post information of.
* @param $show_invisibles
* @return array containing all the information about the last post (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_item_property;
$sql= "SELECT post.post_id, post.forum_id, post.poster_id, post.poster_name, post.post_date, users.lastname, users.firstname, post.visible, thread_properties.visibility AS thread_visibility, forum_properties.visibility AS forum_visibility
FROM $table_posts post, $table_users users, $table_item_property thread_properties, $table_item_property forum_properties
AND post.poster_id=users.user_id
AND post.thread_id=thread_properties.ref
AND post.forum_id=forum_properties.ref
ORDER BY post.post_id DESC";
if ($show_invisibles== true)
$return_array['last_post_id']= $row['post_id'];
$return_array['last_poster_id']= $row['poster_id'];
$return_array['last_post_date']= $row['post_date'];
$return_array['last_poster_name']= $row['poster_name'];
$return_array['last_poster_lastname']= $row['lastname'];
$return_array['last_poster_firstname']= $row['firstname'];
// we have to loop through the results to find the first one that is actually visible to students (forum_category, forum, thread AND post are visible)
if ($row['visible']== '1' AND $row['thread_visibility']== '1' AND $row['forum_visibility']== '1')
$return_array['last_post_id']= $row['post_id'];
$return_array['last_poster_id']= $row['poster_id'];
$return_array['last_post_date']= $row['post_date'];
$return_array['last_poster_name']= $row['poster_name'];
$return_array['last_poster_lastname']= $row['lastname'];
$return_array['last_poster_firstname']= $row['firstname'];
* Retrieve all the threads of a given forum
* @return an array containing all the information about the threads
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_item_property;
// important note: it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
// because we also have thread.* in it. This is because thread has a field locked and post also has the same field
// since we are merging these we would have the post.locked value but in fact we want the thread.locked value
// This is why it is added to the end of the field selection
$sql = "SELECT thread.*, item_properties.*, post.*, users.firstname, users.lastname, users.user_id,
last_poster_users.firstname as last_poster_firstname , last_poster_users.lastname as last_poster_lastname, last_poster_users.user_id as last_poster_user_id, thread.locked as locked
FROM $table_threads thread
INNER JOIN $table_item_property item_properties
ON thread.thread_id=item_properties.ref
AND item_properties.visibility='1'
LEFT JOIN $table_users users
ON thread.thread_poster_id=users.user_id
LEFT JOIN $table_posts post
ON thread.thread_last_post = post.post_id
LEFT JOIN $table_users last_poster_users
ON post.poster_id= last_poster_users.user_id
ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
// important note: it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
// because we also have thread.* in it. This is because thread has a field locked and post also has the same field
// since we are merging these we would have the post.locked value but in fact we want the thread.locked value
// This is why it is added to the end of the field selection
$sql = "SELECT thread.*, item_properties.*, post.*, users.firstname, users.lastname, users.user_id,
last_poster_users.firstname as last_poster_firstname , last_poster_users.lastname as last_poster_lastname, last_poster_users.user_id as last_poster_user_id, thread.locked as locked
FROM $table_threads thread
INNER JOIN $table_item_property item_properties
ON thread.thread_id=item_properties.ref
AND item_properties.visibility<>2
LEFT JOIN $table_users users
ON thread.thread_poster_id=users.user_id
LEFT JOIN $table_posts post
ON thread.thread_last_post = post.post_id
LEFT JOIN $table_users last_poster_users
ON post.poster_id= last_poster_users.user_id
ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
* Retrieve all posts of a given thread
* @return an array containing all the information about the posts of a given thread
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
// note: change these SQL so that only the relevant fields of the user table are used
$sql = "SELECT * FROM $table_posts posts
LEFT JOIN $table_users users
ON posts.poster_id=users.user_id
ORDER BY posts.post_id ASC";
// students can only se the posts that are approved (posts.visible='1')
$sql = "SELECT * FROM $table_posts posts
LEFT JOIN $table_users users
ON posts.poster_id=users.user_id
ORDER BY posts.post_id ASC";
* This function return the html syntax for the image
* @param $image_url The url of the image (absolute or relative)
* @param $alt The alt text (when the images cannot be displayed). http://www.w3.org/TR/html4/struct/objects.html#adef-alt
* @param $title The title of the image. Most browsers display this as 'tool tip'. http://www.w3.org/TR/html4/struct/global.html#adef-title
* @todo this is the same as the Display::xxx function, so it can be removed => all calls have to be changed also
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
function icon($image_url,$alt= '',$title= '')
return '<img src="'. $image_url. '" alt="'. $alt. '" title="'. $title. '" />';
/**************************************************************************
**************************************************************************/
* This function retrieves all the information of a post
* @param $forum_id integer that indicates the forum
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$sql= "SELECT * FROM ". $table_posts. "posts, ". $table_users. " users WHERE posts.poster_id=users.user_id AND posts.post_id='". Database::escape_string($post_id). "'";
* This function retrieves all the information of a thread
* @param $forum_id integer that indicates the forum
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_item_property;
$sql= "SELECT * FROM ". $table_threads. " threads, ". $table_item_property. " item_properties
* This function retrieves all the information of a given forum_id
* @param $forum_id integer that indicates the forum
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
* @deprecated this functionality is now moved to get_forums($forum_id)
global $table_item_property;
$sql= "SELECT * FROM ". $table_forums. " forums, ". $table_item_property. " item_properties
$row['approval_direct_post'] = 0; // we can't anymore change this option, so it should always be activated
* This function retrieves all the information of a given forumcategory id
* @param $forum_id integer that indicates the forum
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $table_categories;
global $table_item_property;
$sql= "SELECT * FROM ". $table_categories. " forumcategories, ". $table_item_property. " item_properties
* This function counts the number of forums inside a given category
* @param $cat_id the id of the forum category
* @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return the number
* of visible forums, $countinvisible=1 would return the number of visible and invisible forums
* @return int the number of forums inside the given category
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$sql= "SELECT count(*) AS number_of_forums FROM ". $table_forums. " WHERE forum_category='". Database::escape_string($cat_id). "'";
return $row['number_of_forums'];
* This function stores a new thread. This is done through an entry in the forum_thread table AND
* in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet))
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $forum_table_attachment;
if(!empty($_FILES['user_upload']['name']))
$post_date= date('Y-m-d H:i:s');
$visible= 0; // the post is not approved yet.
// We first store an entry in the forum_thread table because the thread_id is used in the forum_post table
$sql= "INSERT INTO $table_threads (thread_title, forum_id, thread_poster_id, thread_poster_name, thread_date, thread_sticky)
VALUES ('". $clean_post_title. "',
// if the forum properties tell that the posts have to be approved we have to put the whole thread invisible
// because otherwise the students will see the thread and not the post in the thread.
// we also have to change $visible because the post itself has to be visible in this case (otherwise the teacher would have
// to make the thread visible AND the post
// We now store the content in the table_post table
$sql= "INSERT INTO $table_posts (post_title, post_text, thread_id, forum_id, poster_id, poster_name, post_date, post_notification, post_parent_id, visible)
VALUES ('". $clean_post_title. "',
// now have to update the thread table to fill the thread_last_post field (so that we know when the thread has been updated for the last time)
// Storing the attachments if any
$courseDir = $_course['path']. '/upload/forum';
$updir = $sys_course_path. $courseDir;
// Try to add an extension to the file if it hasn't one
$file_name = $_FILES['user_upload']['name'];
$new_path= $updir. '/'. $new_file_name;
$comment= $values['file_comment'];
// Storing the attachments if any
$sql= 'INSERT INTO '. $forum_table_attachment. '(filename,comment, path, post_id,size) '.
$message.= ' / '. get_lang('FileUploadSucces'). '<br />';
$message.= get_lang('MessageHasToBeApproved'). '<br />';
$message.= get_lang('ReturnTo'). ' <a href="viewforum.php?'. api_get_cidreq(). '&forum='. $values['forum_id']. '&origin='. $origin. '">'. get_lang('Forum'). '</a><br />';
$message.= get_lang('ReturnTo'). ' <a href="viewthread.php?'. api_get_cidreq(). '&forum='. $values['forum_id']. '&origin='. $origin. '&thread='. $last_thread_id. '">'. get_lang('Message'). '</a>';
$reply_info['new_post_id'] = $last_post_id;
if ($values['post_notification'] == 1)
* This function displays the form that is used to add a post. This can be a new thread or a reply.
* @param $action is the parameter that determines if we are
* 1. newthread: adding a new thread (both empty) => No I-frame
* 2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
* 3. replymessage: Replying to a message ($action =replymessage) => I-frame with the complete thread (if enabled) (I first thought to put and I-frame with the message only)
* 4. quote: Quoting a message ($action= quotemessage) => I-frame with the complete thread (if enabled). The message will be in the reply. (I first thought not to put an I-frame here)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
$form->setConstants(array('forum' => '5'));
// settting the form elements
$form->addElement('hidden', 'forum_id', strval(intval($_GET['forum'])));
$form->addElement('hidden', 'thread_id', strval(intval($_GET['thread'])));
// if anonymous posts are allowed we also display a form to allow the user to put his name or username in
if ($current_forum['allow_anonymous']== 1 AND !isset ($_user['user_id']))
$form->addElement('text', 'poster_name', get_lang('Name'));
$form->addElement('text', 'post_title', get_lang('Title'),'class="input_titles"');
$form->addElement('html_editor', 'post_text', get_lang('Text'));
if ($forum_setting['allow_post_notificiation'] AND isset ($_user['user_id']))
$form->addElement('checkbox', 'post_notification', '', get_lang('NotifyByEmail'). ' ('. $_user['mail']. ')');
$form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
//$form->add_resource_button();
$values = $form->exportValues();
$form->addElement('html','<br /><b><div class="row"><div class="label">'. get_lang('AddAnAttachment'). '</div></div></b><br /><br />');
$form->addElement('textarea','file_comment',get_lang('FileComment'),array ('rows' => 4, 'cols' => 34));
$form->addElement('submit', 'SubmitPost', get_lang('Ok'));
$form->add_real_progress_bar('DocumentUpload','user_upload');
if (!empty($form_values))
// if we are quoting a message we have to retrieve the information of the post we are quoting so that
// we can add this as default to the textarea
if (($action== 'quote' OR $action== 'replymessage') and isset ($_GET['post']))
// we also need to put the parent_id of the post in a hidden form when we are quoting or replying to a message (<> reply to a thread !!!)
$form->addElement('hidden', 'post_parent_id', strval(intval($_GET['post']))); // note this has to be cleaned first
// if we are replying or are quoting then we display a default title.
// When we are quoting a message then we have to put that message into the wysiwyg editor.
// note: the style has to be hardcoded here because using class="quote" didn't work
$defaults['post_text']= '<div> </div><div style="margin: 5px;"><div style="font-size: 90%; font-style: italic;">'. get_lang('Quoting'). ' '. $values['firstname']. ' '. $values['lastname']. ':</div><div style="color: #006600; font-size: 90%; font-style: italic; background-color: #FAFAFA; border: #D1D7DC 1px solid; padding: 3px;">'. prepare4display($values['post_text']). '</div></div><div> </div><div> </div>';
$form->setDefaults($defaults);
// the course admin can make a thread sticky (=appears with special icon and always on top)
$form->addRule('post_title', '<div class="required">'. get_lang('ThisFieldIsRequired'), 'required');
if ($current_forum['allow_anonymous']== 1 AND !isset ($_user['user_id']))
$form->addRule('poster_name', '<div class="required">'. get_lang('ThisFieldIsRequired'), 'required');
// The validation or display
$values = $form->exportValues();
if ($forum_setting['show_thread_iframe_on_reply'] and $action<> 'newthread')
* This function stores a reply in the forum_post table.
* It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date)
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
* @version february 2006, dokeos 1.8
global $forum_table_attachment;
$post_date= date('Y-m-d H:i:s');
$visible= 0; // the post is not approved yet.
if(!empty($_FILES['user_upload']['name']))
// We first store an entry in the forum_post table
$sql= "INSERT INTO $table_posts (post_title, post_text, thread_id, forum_id, poster_id, post_date, post_notification, post_parent_id, visible)
|