Dokeos PHP Cross Reference Learning Management Systems

Source: /main/forum/forumfunction.inc.php - 4344 lines - 193012 bytes - Summary - Text - Print

Description: 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 are added: - 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 - sticky messages - new view option: nested view - quoting a message

   1  <?php
   2  
   3  /*
   4  ==============================================================================
   5      Dokeos - elearning and course management software
   6  
   7      Copyright (c) 2004-2008 Dokeos SPRL
   8      Copyright (c) 2003 Ghent University (UGent)
   9      Copyright (c) 2001 Universite catholique de Louvain (UCL)
  10      Copyright (c) various contributors
  11  
  12      For a full list of contributors, see "credits.txt".
  13      The full license can be read in "license.txt".
  14  
  15      This program is free software; you can redistribute it and/or
  16      modify it under the terms of the GNU General Public License
  17      as published by the Free Software Foundation; either version 2
  18      of the License, or (at your option) any later version.
  19  
  20      See the GNU General Public License for more details.
  21  
  22      Contact address: Dokeos, rue du Corbeau, 108, B-1030 Brussels, Belgium
  23      Mail: info@dokeos.com
  24  ==============================================================================
  25  */
  26  
  27  /**
  28  *    These files are a complete rework of the forum. The database structure is
  29  *    based on phpBB but all the code is rewritten. A lot of new functionalities
  30  *    are added:
  31  *     - forum categories and forums can be sorted up or down, locked or made invisible
  32  *    - consistent and integrated forum administration
  33  *     - forum options:     are students allowed to edit their post?
  34  *                         moderation of posts (approval)
  35  *                         reply only forums (students cannot create new threads)
  36  *                         multiple forums per group
  37  *    - sticky messages
  38  *     - new view option: nested view
  39  *     - quoting a message
  40  *
  41  *    @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  42  *    @copyright Ghent University
  43  *    @copyright Patrick Cool
  44  *   @author Julio Montoya <gugli100@gmail.com>, Dokeos Several fixes
  45  *     @package dokeos.forum
  46  *
  47  *     @todo several functions have to be moved to the itemmanager library
  48  * @todo displaying icons => display library
  49  * @todo complete the missing phpdoc the correct order should be
  50  *
  51  *                 some explanation of the function
  52  *                 @param
  53  *                 @return
  54  *                 @todo
  55  *                 @author firstname lastname <email>, organisation
  56  *                 @version (day) month year
  57  *                 @deprecated
  58  */
  59  /**
  60   **************************************************************************
  61   *                        IMPORTANT NOTICE
  62   * Please do not change anything is this code yet because there are still
  63   * some significant code that need to happen and I do not have the time to
  64   * merge files and test it all over again. So for the moment, please do not
  65   * touch the code
  66   *                             -- Patrick Cool <patrick.cool@UGent.be>
  67   **************************************************************************
  68  */
  69  require_once(api_get_path(LIBRARY_PATH).'mail.lib.inc.php');
  70  require_once(api_get_path(LIBRARY_PATH).'text.lib.php');
  71  require_once(api_get_path(INCLUDE_PATH).'/conf/mail.conf.php');
  72  require_once(api_get_path(LIBRARY_PATH).'usermanager.lib.php');
  73  require_once(api_get_path(LIBRARY_PATH).'text.lib.php');
  74  get_notifications_of_user();
  75  
  76  function close_page(){
  77          // close the content div
  78          echo '</div>';
  79  
  80          // secondary actions
  81          echo '<div class="actions"> </div>';
  82  
  83          // display the footer
  84          Display::display_footer();
  85          exit;
  86  }
  87  
  88  
  89  /**
  90  * This function handles all the forum and forumcategories actions. This is a wrapper for the
  91  * forum and forum categories. All this code code could go into the section where this function is
  92  * called but this make the code there cleaner.
  93  * @param
  94  * @return
  95  *
  96  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  97  * @version february 2006, dokeos 1.8
  98  */
  99  function handle_forum_and_forumcategories() {
 100      $action_forum_cat = isset($_GET['action']) ? $_GET['action'] : '';
 101      $post_submit_cat= isset($_POST['SubmitForumCategory']) ?  true : false;
 102      $post_submit_forum= isset($_POST['SubmitForum']) ? true : false;
 103      $get_id=isset($_GET['id']) ? $_GET['id'] : '';
 104      // Adding a forum category
 105      if (($action_forum_cat=='add' && $_GET['content']=='forumcategory') || $post_submit_cat ) {
 106          show_add_forumcategory_form();
 107      }
 108      // Adding a forum
 109      if ((($action_forum_cat=='add' || $action_forum_cat=='edit') && $_GET['content']=='forum') || $post_submit_forum ) {
 110          if ($action_forum_cat=='edit' && $get_id || $post_submit_forum ) {
 111              $inputvalues=get_forums(strval(intval($get_id))); // note: this has to be cleaned first
 112                          
 113                          
 114                  } else {
 115              $inputvalues='';
 116          }
 117          show_add_forum_form($inputvalues);
 118      }
 119      // Edit a forum category
 120      if (($action_forum_cat=='edit' && $_GET['content']=='forumcategory' && isset($_GET['id'])) || (isset($_POST['SubmitEditForumCategory'])) ? true : false )
 121      {
 122          $forum_category=get_forum_categories(strval(intval($_GET['id']))); // note: this has to be cleaned first
 123          show_edit_forumcategory_form($forum_category);
 124          close_page();
 125      }
 126      // Delete a forum category
 127          if (( isset($_GET['action']) && $_GET['action']=='delete') && isset($_GET['content']) && $get_id) {
 128                  $id_forum=Security::remove_XSS($get_id);
 129          $list_threads=get_threads($id_forum);
 130                  
 131          for ( $i=0; $i < count($list_threads); $i++ ) {
 132              $messaje=delete_forum_forumcategory_thread('thread',$list_threads[$i]['thread_id']);
 133              $table_link = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
 134              $sql_link='DELETE FROM '.$table_link.' WHERE ref_id='.$list_threads[$i]['thread_id'].' and type=5 and course_code="'.api_get_course_id().'";';
 135              Database::query($sql_link,__FILE__,__LINE__);
 136          }
 137          $return_message=delete_forum_forumcategory_thread($_GET['content'],$_GET['id']);
 138                  if(api_get_setting('search_enabled') == 'true'){
 139                      //delete from keyword
 140                      $searchkey = new SearchEngineManager();
 141                      $searchkey->idobj = $id_forum;
 142                      $searchkey->course_code = api_get_course_id();
 143                      $searchkey->tool_id = TOOL_FORUM;
 144                      $searchkey->deleteKeyWord();
 145                      
 146                      $forum = new ForumManager($id_forum);
 147                      $forum->search_engine_delete();
 148                  }
 149                  Display :: display_confirmation_message($return_message,false);
 150      }
 151      // Change visibility of a forum or a forum category
 152      if (($action_forum_cat=='invisible' || $action_forum_cat=='visible') && isset($_GET['content']) && isset($_GET['id'])) {
 153          $return_message=change_visibility($_GET['content'], $_GET['id'],$_GET['action']);// note: this has to be cleaned first
 154          Display :: display_confirmation_message($return_message,false);
 155      }
 156      // Change lock status of a forum or a forum category
 157      if (($action_forum_cat=='lock' || $action_forum_cat=='unlock') && isset($_GET['content']) && isset($_GET['id'])) {
 158          $return_message=change_lock_status($_GET['content'], $_GET['id'],$_GET['action']);// note: this has to be cleaned first
 159          Display :: display_confirmation_message($return_message,false);
 160      }
 161      // Move a forum or a forum category
 162      if ($action_forum_cat=='move' && isset($_GET['content']) && isset($_GET['id']) && isset($_GET['direction'])) {
 163          $return_messagshow_add_forum_forme=move_up_down($_GET['content'], $_GET['direction'], $_GET['id']);// note: this has to be cleaned first
 164          Display :: display_confirmation_message($return_message,false);
 165      }
 166  }
 167  /**
 168  * This function displays the form that is used to add a forum category.
 169  *
 170  * @param
 171  * @return
 172  *
 173  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 174  * @version february 2006, dokeos 1.8
 175  */
 176  function show_add_forumcategory_form($inputvalues=array()) {
 177      $gradebook=Security::remove_XSS($_GET['gradebook']);
 178      // initiate the object
 179      $form = new FormValidator('forumcategory','post','index.php?&gradebook='.$gradebook.'');
 180  
 181      // settting the form elements
 182      $form->addElement('header', '', get_lang('AddForumCategory'));
 183      $form->addElement('text', 'forum_category_title', get_lang('Title'),'class="focus" style="width:365px;"');
 184      //$form->applyFilter('forum_category_title', 'html_filter');
 185      //$form->addElement('html_editor', 'forum_category_comment', get_lang('Comment'), null, array('ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200'));
 186      $form->addElement('textarea','forum_category_comment',get_lang('Comment'),array ('rows' => '5', 'cols' => '50'));
 187      //$form->applyFilter('forum_category_comment', 'html_filter');
 188      $form->addElement('style_submit_button', 'SubmitForumCategory', get_lang('CreateCategory'), 'class="add"');
 189  
 190      // setting the rules
 191      $form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
 192  
 193      // The validation or display
 194      if ( $form->validate() ) {
 195          $check = Security::check_token('post');
 196          if ($check) {
 197                 $values = $form->exportValues();
 198                 store_forumcategory($values);
 199          }
 200          Security::clear_token();
 201      } else {
 202          $token = Security::get_token();
 203          $form->addElement('hidden','sec_token');
 204          $form->setConstants(array('sec_token' => $token));
 205          $form->display();
 206          close_page();
 207      }
 208  }
 209  /**
 210  * This function displays the form that is used to add a forum category.
 211  *
 212  * @param
 213  * @return
 214  *
 215  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 216  * @version february 2006, dokeos 1.8
 217  */
 218  function show_add_forum_form($inputvalues=array()) {
 219      global $_course;
 220      $gradebook=Security::remove_XSS($_GET['gradebook']);
 221      $add_params_for_lp = '';
 222      if (isset($_GET['lp_id'])) {
 223      $add_params_for_lp = "&lp_id=".$_GET['lp_id'];
 224      }
 225      // initiate the object
 226      $form = new FormValidator('forumcategory', 'post', 'index.php?gradebook='.$add_params_for_lp.'');
 227      // the header for the form
 228      if (!empty($inputvalues)) {
 229          $form_title = get_lang('EditForum');
 230      } else {
 231          $form_title = get_lang('AddForum');
 232      }
 233      $session_header = isset($_SESSION['session_name']) ? ' ('.$_SESSION['session_name'].') ' : '';
 234      $form->addElement('header', '', $form_title.$session_header);
 235  
 236      // we have a hidden field if we are editing
 237      if (is_array($inputvalues)) {
 238          $my_forum_id=isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
 239          $form->addElement('hidden', 'forum_id', $my_forum_id);
 240      }
 241      // The title of the forum
 242      $form->addElement('text', 'forum_title', get_lang('Title'),'class="focus" style="width:300px;"');
 243      //$form->applyFilter('forum_title', 'html_filter');
 244      // The comment of the forum
 245      //$form->addElement('html_editor', 'forum_comment', get_lang('Comment'), null, array('ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200'));
 246      //$form->applyFilter('forum_comment', 'html_filter');
 247      $form->addElement('textarea','forum_comment',get_lang('Comment'),array ('rows' => '6', 'cols' => '40'));
 248      // dropdown list: Forum Categories
 249      $forum_categories=get_forum_categories();
 250      foreach ($forum_categories as $key=>$value) {
 251          $forum_categories_titles[$value['cat_id']]=$value['cat_title'];
 252      }
 253      $form->addElement('select', 'forum_category', get_lang('InForumCategory'), $forum_categories_titles);
 254      $form->applyFilter('forum_category', 'html_filter');
 255          if(api_get_setting('search_enabled')=='true'){
 256              //TODO: include language file
 257              $form->addElement('hidden','index_document',1);
 258              $form->addElement('hidden','language',api_get_setting('platformLanguage'));
 259              $form->addElement('textarea','search_terms',get_lang('SearchKeywords'),array ('cols'=>'40','rows' => '2'));
 260          }
 261      if ($_course['visibility']==COURSE_VISIBILITY_OPEN_WORLD) {
 262          // This is for vertical
 263          //$form->addElement('radio', 'allow_anonymous', get_lang('AllowAnonymousPosts'), get_lang('Yes'), 1);
 264          //$form->addElement('radio', 'allow_anonymous', '', get_lang('No'), 0);
 265          // This is for horizontal
 266          $group='';
 267          $group[] =& HTML_QuickForm::createElement('radio', 'allow_anonymous',null,get_lang('Yes'),1);
 268          $group[] =& HTML_QuickForm::createElement('radio', 'allow_anonymous',null,get_lang('No'),0);
 269          $form->addGroup($group, 'allow_anonymous_group', get_lang('AllowAnonymousPosts'), '&nbsp;');
 270      }
 271  
 272      // This is for vertical
 273      //$form->addElement('radio', 'students_can_edit', get_lang('StudentsCanEdit'), get_lang('Yes'), 1);
 274      //$form->addElement('radio', 'students_can_edit', '', get_lang('No'), 0);
 275      // This is for horizontal
 276  
 277              /*        if (document.getElementById('id_qualify').style.display == 'none') {
 278                      document.getElementById('id_qualify').style.display = 'block';
 279                      document.getElementById('plus').innerHTML='&nbsp;'.Display::return_icon('div_hide.gif').'&nbsp;".get_lang('AddAnAttachment')."';
 280                  } else {
 281                  document.getElementById('options').style.display = 'none';
 282                  document.getElementById('plus').innerHTML='&nbsp;'.Display::return_icon('div_show.gif').'&nbsp;".get_lang('AddAnAttachment')."';
 283                  }*/
 284  
 285      $form->addElement('html', '<div class="row"><div class="label">');
 286      $form->addElement('html', '<br /><div id="plus"><a href="javascript://" onclick="advanced_parameters()" ><span id="plus_minus">&nbsp;'.Display::return_icon('div_show.gif',get_lang('Show'),array('style'=>'vertical-align:middle')).'&nbsp;'.get_lang('AdvancedParameters').'</span></a></div>','');
 287      $form->addElement('html','</div><div class="formw"></div></div>');
 288      $form->addElement('html','<div id="options" style="display:none">');
 289  
 290  
 291      $group='';
 292      $group[] =& HTML_QuickForm::createElement('radio', 'students_can_edit',null,get_lang('Yes'),1);
 293      $group[] =& HTML_QuickForm::createElement('radio', 'students_can_edit',null,get_lang('No'),0);
 294      $form->addGroup($group, 'students_can_edit_group', get_lang('StudentsCanEdit'), '&nbsp;');
 295  
 296      // This is for vertical
 297      //$form->addElement('radio', 'approval_direct', get_lang('ApprovalDirect'), get_lang('Approval'), 1);
 298      //$form->addElement('radio', 'approval_direct', '', get_lang('Direct'), 0);
 299      // This is for horizontal
 300      $group='';
 301      $group[] =& HTML_QuickForm::createElement('radio', 'approval_direct',null,get_lang('Approval'),1);
 302      $group[] =& HTML_QuickForm::createElement('radio', 'approval_direct',null,get_lang('Direct'),0);
 303      //$form->addGroup($group, 'approval_direct_group', get_lang('ApprovalDirect'), '&nbsp;');
 304  
 305  
 306      // This is for vertical
 307      //$form->addElement('radio', 'allow_attachments', get_lang('AllowAttachments'), get_lang('Yes'), 1);
 308      //$form->addElement('radio', 'allow_attachments', '', get_lang('No'), 0);
 309      // This is for horizontal
 310      $group='';
 311      $group[] =& HTML_QuickForm::createElement('radio', 'allow_attachments',null,get_lang('Yes'),1);
 312      $group[] =& HTML_QuickForm::createElement('radio', 'allow_attachments',null,get_lang('No'),0);
 313      //$form->addGroup($group, 'allow_attachments_group', get_lang('AllowAttachments'), '&nbsp;');
 314  
 315      // This is for vertical
 316      //$form->addElement('radio', 'allow_new_threads', get_lang('AllowNewThreads'), 1, get_lang('Yes'));
 317      //$form->addElement('radio', 'allow_new_threads', '', 0, get_lang('No'));
 318      // This is for horizontal
 319      $group='';
 320      $group[] =& HTML_QuickForm::createElement('radio', 'allow_new_threads',null, get_lang('Yes'),1);
 321      $group[] =& HTML_QuickForm::createElement('radio', 'allow_new_threads',null, get_lang('No'),0);
 322      $form->addGroup($group, 'allow_new_threads_group', get_lang('AllowNewThreads'), '&nbsp;');
 323  
 324      $group='';
 325      $group[] =& HTML_QuickForm::createElement('radio', 'default_view_type', null, get_lang('Flat'), 'flat');
 326      $group[] =& HTML_QuickForm::createElement('radio', 'default_view_type', null, get_lang('Threaded'), 'threaded');
 327      $group[] =& HTML_QuickForm::createElement('radio', 'default_view_type', null, get_lang('Nested'), 'nested');
 328      $form->addGroup($group, 'default_view_type_group', get_lang('DefaultViewType'), '&nbsp;');
 329  
 330      $form->addElement('static','Group', '<br /><strong>'.get_lang('GroupSettings').'</strong>');
 331  
 332      // dropdown list: Groups
 333      $groups=GroupManager::get_group_list();
 334      $groups_titles[0]=get_lang('NotAGroupForum');
 335      foreach ($groups as $key=>$value) {
 336          $groups_titles[$value['id']]=$value['name'];
 337      }
 338      $form->addElement('select', 'group_forum', get_lang('ForGroup'), $groups_titles);
 339  
 340      // Public or private group forum
 341      $group='';
 342      $group[] =& HTML_QuickForm::createElement('radio', 'public_private_group_forum', null, get_lang('Public'), 'public');
 343      $group[] =& HTML_QuickForm::createElement('radio', 'public_private_group_forum', null, get_lang('Private'), 'private');
 344      $form->addGroup($group, 'public_private_group_forum_group', get_lang('PublicPrivateGroupForum'), '&nbsp;');
 345  
 346  
 347       // Forum image
 348       $form->add_progress_bar();
 349       if (isset($inputvalues['forum_image']) && strlen($inputvalues['forum_image']) > 0) {
 350  
 351           $image_path = api_get_path(WEB_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$inputvalues['forum_image'];
 352           $image_size = api_getimagesize($image_path);
 353  
 354           $img_attributes = '';
 355           if (!empty($image_size)) {
 356               if ($image_size[0] > 100 || $image_size[1] > 100) {
 357                  //limit display width and height to 100px
 358                  $img_attributes = 'width="100" height="100"';
 359               }
 360                $show_preview_image='<img src="'.$image_path.'" '.$img_attributes.'>';
 361               $div = '<div class="row">
 362               <div class="label">'.get_lang('PreviewImage').'</div>
 363               <div class="formw">
 364               '.$show_preview_image.'
 365               </div>
 366               </div>';
 367  
 368               $form->addElement('html', $div .'<br/>');
 369                $form->addElement('checkbox', 'remove_picture', null, get_lang('DelImage'));
 370           }
 371  
 372       }
 373       $forum_image=isset($inputvalues['forum_image']) ? $inputvalues['forum_image'] : '';
 374       $form->addElement('file', 'picture', ($forum_image != '' ? get_lang('UpdateImage') : get_lang('AddImage')));
 375       $form->addRule('picture', get_lang('OnlyImagesAllowed'), 'filetype', array ('jpg', 'jpeg', 'png', 'gif'));
 376       $form->addElement('html','</div>');
 377  
 378      // The OK button
 379      if (isset($_GET['id']) && $_GET['action']=='edit'){
 380          $class='save';
 381          $text=get_lang('ModifyForum');
 382      }else{
 383          $class='add';
 384          $text=get_lang('CreateForum');
 385      }
 386      $form->addElement('style_submit_button', 'SubmitForum', $text, 'class="'.$class.'"');
 387      // setting the rules
 388      $form->addRule('forum_title', get_lang('ThisFieldIsRequired'), 'required');
 389      $form->addRule('forum_category', get_lang('ThisFieldIsRequired'), 'required');
 390  
 391      global $charset;
 392  
 393      // settings the defaults
 394      if (!is_array($inputvalues)) {
 395          $defaults['allow_anonymous_group']['allow_anonymous']=0;
 396          $defaults['students_can_edit_group']['students_can_edit']=0;
 397          $defaults['approval_direct_group']['approval_direct']=0;
 398          $defaults['allow_attachments_group']['allow_attachments']=1;
 399          $defaults['allow_new_threads_group']['allow_new_threads']=0;
 400          $defaults['default_view_type_group']['default_view_type']=api_get_setting('default_forum_view');
 401          $defaults['public_private_group_forum_group']['public_private_group_forum']='public';
 402                  $defaults['search_terms'] = '';
 403          if (isset($_GET['forumcategory'])) {
 404              $defaults['forum_category']=Security::remove_XSS($_GET['forumcategory']);
 405          }
 406      } else {   // the default values when editing = the data in the table
 407          $defaults['forum_id']=isset($inputvalues['forum_id']) ? $inputvalues['forum_id'] : null;
 408          $defaults['forum_title']=prepare4display(api_html_entity_decode(isset($inputvalues['forum_title']) ? $inputvalues['forum_title'] : null,ENT_QUOTES,$charset));
 409          $defaults['forum_comment']=prepare4display(isset($inputvalues['forum_comment'])?$inputvalues['forum_comment']:null);
 410          $defaults['forum_category']=isset($inputvalues['forum_category']) ? $inputvalues['forum_category'] : null;
 411          $defaults['allow_anonymous_group']['allow_anonymous']=isset($inputvalues['allow_anonymous']) ? $inputvalues['allow_anonymous'] :null;
 412          $defaults['students_can_edit_group']['students_can_edit']=isset($inputvalues['allow_edit'])?$inputvalues['allow_edit']:null;
 413          $defaults['approval_direct_group']['approval_direct']=isset($inputvalues['approval_direct_post'])?$inputvalues['approval_direct_post']:null;
 414          $defaults['allow_attachments_group']['allow_attachments']=isset($inputvalues['allow_attachments'])?$inputvalues['allow_attachments']:null;
 415          $defaults['allow_new_threads_group']['allow_new_threads']=isset($inputvalues['allow_new_threads'])?$inputvalues['allow_new_threads']:null;
 416          $defaults['default_view_type_group']['default_view_type']=isset($inputvalues['default_view'])?$inputvalues['default_view']:null;
 417          $defaults['public_private_group_forum_group']['public_private_group_forum']=isset($inputvalues['forum_group_public_private'])?$inputvalues['forum_group_public_private']:null;
 418          $defaults['group_forum']=isset($inputvalues['forum_of_group'])?$inputvalues['forum_of_group']:null;
 419                  require_once api_get_path(LIBRARY_PATH).'searchengine.lib.php';
 420                  //get the keyword
 421                  $searchkey = new SearchEngineManager();
 422                  $keyword = $searchkey->getKeyWord(TOOL_FORUM, $inputvalues['forum_id']);
 423                  $defaults['search_terms']=$keyword;
 424                  
 425      }
 426      $form->setDefaults($defaults);
 427      // The validation or display
 428      if( $form->validate() ) {
 429          $check = Security::check_token('post');
 430          if ($check) {
 431              $values = $form->exportValues();
 432                 $return_message = store_forum($values);
 433                 Display :: display_confirmation_message($return_message);
 434          }
 435          Security::clear_token();
 436      } else {
 437  
 438              $token = Security::get_token();
 439              $form->addElement('hidden','sec_token');
 440              $form->setConstants(array('sec_token' => $token));
 441              $form->display();
 442              close_page();
 443      }
 444  }
 445  
 446  /**
 447   * This function deletes the forum image if exists
 448  *
 449  * @param int forum id
 450  * @return boolean true if success
 451  * @author Julio Montoya <gugli100@gmail.com>, Dokeos
 452  * @version february 2006, dokeos 1.8
 453  */
 454  function delete_forum_image($forum_id)
 455  {
 456      $table_forums = Database::get_course_table(TABLE_FORUM);
 457      $forum_id = Database::escape_string($forum_id);
 458      $sql="SELECT forum_image FROM $table_forums WHERE forum_id = '".$forum_id."' ";
 459      $result=Database::query($sql,__FILE__,__LINE__);
 460      $row=Database::fetch_array($result);
 461      if ($row['forum_image']!='') {
 462          $del_file = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/upload/forum/images/'.$row['forum_image'];
 463          return @unlink($del_file);
 464      } else {
 465          return false;
 466      }
 467  
 468  }
 469  
 470  
 471  /**
 472  * This function displays the form that is used to edit a forum category.
 473  * This is more or less a copy from the show_add_forumcategory_form function with the only difference that is uses
 474  * some default values. I tried to have both in one function but this gave problems with the handle_forum_and_forumcategories function
 475  * (storing was done twice)
 476  *
 477  * @param
 478  * @return
 479  *
 480  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 481  * @version february 2006, dokeos 1.8
 482  */
 483  function show_edit_forumcategory_form($inputvalues=array()) {
 484      // initiate the object
 485      $gradebook=Security::remove_XSS($_GET['gradebook']);
 486      $form = new FormValidator('forumcategory','post','index.php?&gradebook='.$gradebook.'');
 487  
 488      // settting the form elements
 489      $form->addElement('header', '', get_lang('EditForumCategory'));
 490      $form->addElement('hidden', 'forum_category_id');
 491      $form->addElement('text', 'forum_category_title', get_lang('Title'),'class="focus" style="width:365px;"');
 492      //$form->applyFilter('forum_category_title', 'html_filter');
 493      //$form->addElement('html_editor', 'forum_category_comment', get_lang('Comment'), null, array('ToolbarSet' => 'Forum', 'Width' => '98%', 'Height' => '200'));
 494      $form->addElement('textarea','forum_category_comment',get_lang('Comment'),array ('rows' => '5', 'cols' => '50'));
 495      //$form->applyFilter('forum_category_comment', 'html_filter');
 496      $form->addElement('style_submit_button', 'SubmitEditForumCategory',get_lang('ModifyCategory'), 'class="save"');
 497      global $charset;
 498      // setting the default values
 499      $defaultvalues['forum_category_id']=$inputvalues['cat_id'];
 500  
 501      $defaultvalues['forum_category_title']=prepare4display(api_html_entity_decode($inputvalues['cat_title'],ENT_QUOTES,$charset));
 502      $defaultvalues['forum_category_comment']=prepare4display($inputvalues['cat_comment']);
 503      $form->setDefaults($defaultvalues);
 504  
 505      // setting the rules
 506      $form->addRule('forum_category_title', get_lang('ThisFieldIsRequired'), 'required');
 507  
 508      // The validation or display
 509      if ( $form->validate() ) {
 510          $check = Security::check_token('post');
 511          if ($check) {
 512                 $values = $form->exportValues();
 513                store_forumcategory($values);
 514          }
 515          Security::clear_token();
 516      } else {
 517          $token = Security::get_token();
 518          $form->addElement('hidden','sec_token');
 519          $form->setConstants(array('sec_token' => $token));
 520          $form->display();
 521      }
 522  }
 523  
 524  
 525  
 526  /**
 527  * This function stores the forum category in the database. The new category is added to the end.
 528  *
 529  * @param
 530  * @return
 531  *
 532  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 533  * @version february 2006, dokeos 1.8
 534  */
 535  function store_forumcategory($values) {
 536      global $table_categories;
 537      global $_course;
 538      global $_user;
 539  
 540      // find the max cat_order. The new forum category is added at the end => max cat_order + &
 541      $sql="SELECT MAX(cat_order) as sort_max FROM ".Database::escape_string($table_categories);
 542      $result=Database::query($sql,__FILE__,__LINE__);
 543      $row=Database::fetch_array($result);
 544      $new_max=$row['sort_max']+1;
 545      $session_id = api_get_session_id();
 546  
 547      $clean_cat_title=Database::escape_string(Security::remove_XSS($values['forum_category_title']));
 548  
 549      if (isset($values['forum_category_id'])) { // storing an edit
 550          $sql="UPDATE ".$table_categories." SET cat_title='".$clean_cat_title."', cat_comment='".Database::escape_string(Security::remove_XSS(stripslashes(api_html_entity_decode($values['forum_category_comment'])),COURSEMANAGERLOWSECURITY))."' WHERE cat_id='".Database::escape_string($values['forum_category_id'])."'";
 551          Database::query($sql,__FILE__,__LINE__);
 552          $last_id=Database::insert_id();
 553          api_item_property_update(api_get_course_info(), TOOL_FORUM_CATEGORY, $values['forum_category_id'], 'ForumCategoryUpdated', api_get_user_id());
 554          $return_message=get_lang('ForumCategoryEdited');
 555          $return_message.= ':'.'<a href="index.php?'.api_get_cidreq().'">'.get_lang('BackToForum').'</a>';
 556          echo '<div class="confirmation-message rounded">'.$return_message.'</div>';
 557      } else {
 558          $sql = "INSERT INTO ".$table_categories." (cat_title, cat_comment, cat_order, session_id) VALUES ('".$clean_cat_title."','".Database::escape_string(Security::remove_XSS(stripslashes(api_html_entity_decode($values['forum_category_comment'])),COURSEMANAGERLOWSECURITY))."','".Database::escape_string($new_max)."','".Database::escape_string($session_id)."')";
 559          Database::query($sql,__FILE__,__LINE__);
 560          $last_id = Database::insert_id();
 561          if ($last_id > 0) {
 562              api_item_property_update(api_get_course_info(), TOOL_FORUM_CATEGORY, $last_id, 'ForumCategoryAdded', api_get_user_id());
 563          }
 564          $return_message=get_lang('ForumCategoryAdded');
 565      }
 566      //Display :: display_confirmation_message($return_message);
 567  }
 568  
 569  /**
 570  * This function stores the forum in the database. The new forum is added to the end.
 571  *
 572  * @param
 573  * @return
 574  *
 575  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 576  * @version february 2006, dokeos 1.8
 577  */
 578  function store_forum($values) {
 579      global $_course;
 580      global $_user;
 581          
 582      $table_forums = Database::get_course_table(TABLE_FORUM);
 583  
 584      // find the max forum_order for the given category. The new forum is added at the end => max cat_order + &
 585      if (is_null($values['forum_category'])) {
 586          $new_max=null;
 587      } else {
 588          $sql="SELECT MAX(forum_order) as sort_max FROM ".$table_forums." WHERE forum_category='".Database::escape_string($values['forum_category'])."'";
 589          $result=Database::query($sql,__FILE__,__LINE__);
 590          $row=Database::fetch_array($result);
 591          $new_max=$row['sort_max']+1;
 592      }
 593  
 594  
 595      $session_id = api_get_session_id();
 596  
 597      $clean_title = Database::escape_string(Security::remove_XSS($values['forum_title']));
 598  
 599      // forum images
 600  
 601      $image_moved=false;
 602      if (!empty($_FILES['picture']['name'])) {
 603          $upload_ok = process_uploaded_file($_FILES['picture']);
 604          $has_attachment=true;
 605      } else {
 606          $image_moved=true;
 607      }
 608  
 609      // remove existing picture if asked
 610      if (!empty($_POST['remove_picture'])) {
 611          delete_forum_image($values['forum_id']);
 612      }
 613  
 614      if (isset($upload_ok)) {
 615          if ($has_attachment) {
 616              $courseDir   = $_course['path'].'/upload/forum/images';
 617              $sys_course_path = api_get_path(SYS_COURSE_PATH);
 618              $updir = $sys_course_path.$courseDir;
 619              // Try to add an extension to the file if it hasn't one
 620              $new_file_name = add_ext_on_mime(Database::escape_string($_FILES['picture']['name']), $_FILES['picture']['type']);
 621              // user's file name
 622              $file_name =$_FILES['picture']['name'];
 623  
 624              if (!filter_extension($new_file_name)) {
 625                   //Display :: display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
 626                   $image_moved=false;
 627              } else {
 628                   $file_extension = explode('.', $_FILES['picture']['name']);
 629                   $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
 630                   $new_file_name = uniqid('').'.'.$file_extension;
 631                   $new_path=$updir.'/'.$new_file_name;
 632                   $result= @move_uploaded_file($_FILES['picture']['tmp_name'], $new_path);
 633                   // Storing the attachments if any
 634                   if ($result) {
 635                           $image_moved=true;
 636                   }
 637              }
 638          }
 639      }
 640  
 641      if (isset($values['forum_id'])) {
 642          $sql_image=isset($sql_image)?$sql_image:'';
 643          $new_file_name=isset($new_file_name) ? $new_file_name:'';
 644            if ($image_moved) {
 645                if(empty($_FILES['picture']['name'])){
 646                    $sql_image=" ";
 647                } else {
 648                    $sql_image=" forum_image='".Database::escape_string($new_file_name)."', ";
 649                    delete_forum_image($values['forum_id']);
 650                }
 651          }
 652                  
 653          // storing an edit
 654          $sql="UPDATE ".$table_forums." SET
 655                  forum_title='".$clean_title."',
 656                  ".$sql_image."
 657                  forum_comment='".Database::escape_string(Security::remove_XSS(stripslashes(api_html_entity_decode($values['forum_comment'])),COURSEMANAGERLOWSECURITY))."',
 658                  forum_category='".Database::escape_string($values['forum_category'])."',
 659                  allow_anonymous='".Database::escape_string(isset($values['allow_anonymous_group']['allow_anonymous'])?$values['allow_anonymous_group']['allow_anonymous']:null)."',
 660                  allow_edit='".Database::escape_string($values['students_can_edit_group']['students_can_edit'])."',
 661                  approval_direct_post='".Database::escape_string(isset($values['approval_direct_group']['approval_direct'])?$values['approval_direct_group']['approval_direct']:null)."',
 662                  allow_attachments='".Database::escape_string(isset($values['allow_attachments_group']['allow_attachments'])?$values['allow_attachments_group']['allow_attachments']:null)."',
 663                  allow_new_threads='".Database::escape_string($values['allow_new_threads_group']['allow_new_threads'])."',
 664                  forum_group_public_private='".Database::escape_string($values['public_private_group_forum_group']['public_private_group_forum'])."',
 665                  default_view='".Database::escape_string($values['default_view_type_group']['default_view_type'])."',
 666                  forum_of_group='".Database::escape_string($values['group_forum'])."'
 667              WHERE forum_id='".Database::escape_string($values['forum_id'])."'";
 668              Database::query($sql,__FILE__,__LINE__);
 669              api_item_property_update($_course, TOOL_FORUM, Database::escape_string($values['forum_id']), 'ForumUpdated', api_get_user_id());
 670              
 671                  if (api_get_setting('search_enabled') == 'true' && extension_loaded('xapian')) {
 672                         //update search engine keyword
 673                          $searchkey = new SearchEngineManager();
 674                          $searchkey->idobj = (int)$values['forum_id'];
 675                          $searchkey->course_code = api_get_course_id();
 676                          $searchkey->tool_id = TOOL_FORUM;
 677                          $searchkey->value = Security::remove_XSS($_POST['search_terms']);
 678                          $searchkey->updateKeyWord();
 679                      
 680                          $forum = new ForumManager((int)($values['forum_id']));
 681                          $forum->search_engine_edit();
 682                  } 
 683                  $return_message=get_lang('ForumEdited');
 684      } else {
 685          $sql_image='';
 686          if ($image_moved) {
 687              $new_file_name=isset($new_file_name)?$new_file_name:'';
 688              $sql_image="'".$new_file_name."', ";
 689          }
 690          $b=$values['forum_comment'];
 691                  
 692          $sql="INSERT INTO ".$table_forums."
 693              (forum_title, forum_image, 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)
 694              VALUES ('".Security::remove_XSS($clean_title)."',
 695                  ".$sql_image."
 696                  '".Database::escape_string(isset($values['forum_comment'])?Security::remove_XSS(stripslashes(api_html_entity_decode($values['forum_comment'])),COURSEMANAGERLOWSECURITY):null)."',
 697                  '".Database::escape_string(isset($values['forum_category'])?$values['forum_category']:null)."',
 698                  '".Database::escape_string(isset($values['allow_anonymous_group']['allow_anonymous'])?$values['allow_anonymous_group']['allow_anonymous']:null)."',
 699                  '".Database::escape_string(isset($values['students_can_edit_group']['students_can_edit'])?$values['students_can_edit_group']['students_can_edit']:null)."',
 700                  '".Database::escape_string(isset($values['approval_direct_group']['approval_direct'])?$values['approval_direct_group']['approval_direct']:null)."',
 701                  '".Database::escape_string(isset($values['allow_attachments_group']['allow_attachments'])?$values['allow_attachments_group']['allow_attachments']:null)."',
 702                  '".Database::escape_string(isset($values['allow_new_threads_group']['allow_new_threads'])?$values['allow_new_threads_group']['allow_new_threads']:null)."',
 703                  '".Database::escape_string(isset($values['default_view_type_group']['default_view_type'])?$values['default_view_type_group']['default_view_type']:null)."',
 704                  '".Database::escape_string(isset($values['group_forum'])?$values['group_forum']:null)."',
 705                  '".Database::escape_string(isset($values['public_private_group_forum_group']['public_private_group_forum'])?$values['public_private_group_forum_group']['public_private_group_forum']:null)."',
 706                  '".Database::escape_string(isset($new_max)?$new_max:null)."',
 707                  ".intval($session_id).")";
 708          Database::query($sql,__FILE__,__LINE__);
 709          $last_id = Database::insert_id();
 710          if ($last_id > 0) {
 711                        api_item_property_update($_course, TOOL_FORUM, $last_id, 'ForumAdded', api_get_user_id());
 712          }
 713          if (isset($_SESSION['oLP']->lp_id) && $last_id > 0) {            
 714                        // Get the previous item ID
 715                        $parent = 0;
 716                        $previous = $_SESSION['oLP']->select_previous_item_id();
 717                        // Add quiz as Lp Item
 718                        $_SESSION['oLP']->add_item($parent, $previous, TOOL_FORUM, $last_id, $clean_title, '');
 719          }
 720                  if (api_get_setting('search_enabled') == 'true' && extension_loaded('xapian')) {
 721                        //save search engine keyword
 722                        $searchkey = new SearchEngineManager();
 723                        $searchkey->idobj = $last_id;
 724                        $searchkey->course_code = api_get_course_id();
 725                        $searchkey->tool_id = TOOL_FORUM;
 726                        $searchkey->value = $_POST['search_terms'];
 727                        $searchkey->save();
 728  
 729                        $forum = new ForumManager($last_id);
 730                        $forum->search_engine_save();
 731                  }
 732          $return_message = get_lang('ForumAdded');
 733      }
 734      return $return_message;
 735  }
 736  
 737  /**
 738  * This function deletes a forum or a forum category
 739  * This function currently does not delete the forums inside the category, nor the threads and replies inside these forums.
 740  * For the moment this is the easiest method and it has the advantage that it allows to recover fora that were acidently deleted
 741  * when the forum category got deleted.
 742  *
 743  * @param $content = what we are deleting (a forum or a forum category)
 744  * @param $id The id of the forum category that has to be deleted.
 745  *
 746  * @todo write the code for the cascading deletion of the forums inside a forum category and also the threads and replies inside these forums
 747  * @todo config setting for recovery or not (see also the documents tool: real delete or not).
 748  *
 749  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 750  * @version february 2006, dokeos 1.8
 751  */
 752  function delete_forum_forumcategory_thread($content, $id) {
 753      global $_course;
 754      $table_forums = Database::get_course_table(TABLE_FORUM);
 755      $table_forums_post = Database::get_course_table(TABLE_FORUM_POST);
 756      $table_forum_thread = Database::get_course_table(TABLE_FORUM_THREAD);
 757  
 758      // delete all attachment file about this tread id
 759      $sql = "SELECT post_id FROM $table_forums_post WHERE thread_id = '".(int)$id."' ";
 760      $res = Database::query($sql,__FILE__,__LINE__);
 761      while ($poster_id = Database::fetch_row($res)) {
 762          delete_attachment($poster_id[0]);
 763      }
 764  
 765      if ($content=='forumcategory') {
 766          $tool_constant=TOOL_FORUM_CATEGORY;
 767          $return_message=get_lang('ForumCategoryDeleted');
 768  
 769          if (!empty($forum_list)){
 770              $sql="SELECT forum_id FROM ". $table_forums . "WHERE forum_category='".$id."'";
 771              $result = Database::query($sql, __FILE__, __LINE__);
 772              $row = Database::fetch_array($result);
 773              foreach ($row as $arr_forum) {
 774                  $forum_id = $arr_forum['forum_id'];
 775                  api_item_property_update($_course,'forum',$forum_id,'delete',api_get_user_id());
 776              }
 777          }
 778      }
 779      if ($content=='forum') {
 780          $tool_constant=TOOL_FORUM;
 781          $return_message=get_lang('ForumDeleted');
 782  
 783          if (!empty($number_threads)){
 784              $sql="SELECT thread_id FROM". $table_forum_thread . "WHERE forum_id='".$id."'";
 785              $result = Database::query($sql, __FILE__, __LINE__);
 786              $row = Database::fetch_array($result);
 787              foreach ($row as $arr_forum) {
 788                  $forum_id = $arr_forum['thread_id'];
 789                  api_item_property_update($_course,'forum_thread',$forum_id,'delete',api_get_user_id());
 790              }
 791          }
 792      }
 793      if ($content=='thread') {
 794          $tool_constant=TOOL_FORUM_THREAD;
 795          $return_message=get_lang('ThreadDeleted');
 796      }
 797      api_item_property_update($_course,$tool_constant,$id,'delete',api_get_user_id()); // note: check if this returns a true and if so => return $return_message, if not => return false;
 798      return $return_message;
 799  }
 800  
 801  /**
 802  * This function deletes a forum post. This separate function is needed because forum posts do not appear in the item_property table (yet)
 803  * and because deleting a post also has consequence on the posts that have this post as parent_id (they are also deleted).
 804  * an alternative would be to store the posts also in item_property and mark this post as deleted (visibility = 2).
 805  * We also have to decrease the number of replies in the thread table
 806  *
 807  * @param $post_id the id of the post that will be deleted
 808  *
 809  * @todo write recursive function that deletes all the posts that have this message as parent
 810  *
 811  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 812  * @version february 2006, dokeos 1.8
 813  */
 814  function delete_post($post_id) {
 815      global $table_posts;
 816      global $table_threads;
 817  
 818      $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.
 819      Database::query($sql,__FILE__,__LINE__);
 820  
 821      //delete attachment file about this post id
 822      delete_attachment($post_id);
 823  
 824      $last_post_of_thread=check_if_last_post_of_thread(strval(intval($_GET['thread'])));
 825  
 826      if (is_array($last_post_of_thread)) {
 827          // Decreasing the number of replies for this thread and also changing the last post information
 828          $sql="UPDATE $table_threads SET thread_replies=thread_replies-1,
 829                      thread_last_post='".Database::escape_string($last_post_of_thread['post_id'])."',
 830                      thread_date='".Database::escape_string($last_post_of_thread['post_date'])."'
 831              WHERE thread_id='".Database::escape_string($_GET['thread'])."'";
 832          Database::query($sql,__FILE__,__LINE__);
 833          return 'PostDeleted';
 834      }
 835      if ($last_post_of_thread==false) {
 836          // we deleted the very single post of the thread so we need to delete the entry in the thread table also.
 837          $sql="DELETE FROM $table_threads WHERE thread_id='".Database::escape_string($_GET['thread'])."'";
 838          Database::query($sql,__FILE__,__LINE__);
 839          return 'PostDeletedSpecial';
 840      }
 841  }
 842  
 843  
 844  /**
 845  * This function gets the all information of the last (=most recent) post of the thread
 846  * This can be done by sorting the posts that have the field thread_id=$thread_id and sort them by post_date
 847  *
 848  * @param $thread_id the id of the thread we want to know the last post of.
 849  * @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
 850  *
 851  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 852  * @version february 2006, dokeos 1.8
 853  */
 854  function check_if_last_post_of_thread($thread_id) {
 855      global $table_posts;
 856  
 857      $sql="SELECT * FROM $table_posts WHERE thread_id='".Database::escape_string($thread_id)."' ORDER BY post_date DESC";
 858      $result=Database::query($sql,__FILE__,__LINE__);
 859      if ( Database::num_rows($result)>0 ) {
 860          $row=Database::fetch_array($result);
 861          return $row;
 862      } else {
 863          return false;
 864      }
 865  }
 866  
 867  
 868  /**
 869  * This function takes care of the display of the visibility icon
 870  *
 871  * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
 872  * @param $id the id of the content we want to make invisible
 873  * @param $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
 874  * @param array  additional attributes for the link
 875  * @param bool   optional, if the function return or display a content html
 876  * @return void|string
 877  *
 878  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 879  * @version february 2006, dokeos 1.8
 880  */
 881  function display_visible_invisible_icon($content, $id, $current_visibility_status, $additional_url_parameters='', $return = false) {
 882      global $origin;
 883      $gradebook=Security::remove_XSS($_GET['gradebook']);
 884      $id = Security::remove_XSS($id);
 885          $output = '';
 886      if ($current_visibility_status=='1') {
 887          $link  = '<a class="action" href="'.api_get_self().'?'.api_get_cidreq().'&';
 888          if (is_array($additional_url_parameters)) {
 889              foreach ($additional_url_parameters as $key=>$value) {
 890                  $link .= $key.'='.$value.'&amp;';
 891              }
 892          }
 893          $link .= 'action=invisible&amp;content='.$content.'&amp;id='.$id.'&gradebook='.$gradebook.'&amp;origin='.$origin.'">'.Display::return_icon('pixel.gif',get_lang('MakeInvisible'), array('class' => 'actionplaceholdericon actionvisible')).'</a>';
 894                  $output = $link;
 895      }
 896      if ($current_visibility_status=='0') {
 897          $link = '<a class="action" href="'.api_get_self().'?'.api_get_cidreq().'&';
 898          if (is_array($additional_url_parameters)) {
 899              foreach ($additional_url_parameters as $key=>$value) {
 900                  $link .= $key.'='.$value.'&amp;';
 901              }
 902          }
 903          $link .= 'action=visible&amp;content='.$content.'&amp;id='.$id.'&gradebook='.$gradebook.'&amp;origin='.$origin.'">'.Display::return_icon('pixel.gif',get_lang('MakeVisible'), array('class' => 'actionplaceholdericon actionvisible invisible')).'</a>';
 904                  $output = $link;
 905      }
 906          if ($return) {
 907              return $output;
 908          } else {
 909              echo $output;
 910          }
 911  }
 912  
 913  /**
 914  * This function takes care of the display of the lock icon
 915  *
 916  * @param $content what is it that we want to (un)lock: forum category, forum, thread, post
 917  * @param $id the id of the content we want to (un)lock
 918  * @param $current_visibility_status what is the current status of the visibility (0 = invisible, 1 = visible)
 919  * @param array  additional attributes for the link
 920  * @param bool   optional, if the function return or display a content html
 921  * @return void|string
 922  *
 923  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 924  * @version february 2006, dokeos 1.8
 925  */
 926  function display_lock_unlock_icon($content, $id, $current_lock_status, $additional_url_parameters='', $return = false)
 927  {
 928      $id = Security::remove_XSS($id);
 929          $output = '';
 930      if ($current_lock_status=='1')
 931      {
 932          $link = '<a class="action" href="'.api_get_self().'?'.api_get_cidreq().'&';
 933          if (is_array($additional_url_parameters))
 934          {
 935              foreach ($additional_url_parameters as $key=>$value)
 936              {
 937                  $link .= $key.'='.$value.'&amp;';
 938              }
 939          }
 940          $link .= 'action=unlock&amp;content='.$content.'&amp;id='.$id.'">'.Display::return_icon('pixel.gif',get_lang('Unlock'), array('class' => 'actionplaceholdericon actionlock')).'</a>';
 941                  $output = $link;
 942      }
 943      if ($current_lock_status=='0')
 944      {
 945          $link = '<a class="action" href="'.api_get_self().'?'.api_get_cidreq().'&';
 946          if (is_array($additional_url_parameters))
 947          {
 948              foreach ($additional_url_parameters as $key=>$value)
 949              {
 950                  $link .= $key.'='.$value.'&amp;';
 951              }
 952          }
 953          $link .= 'action=lock&amp;content='.$content.'&amp;id='.$id.'">'.Display::return_icon('pixel.gif',get_lang('Lock'), array('class' => 'actionplaceholdericon actionunlock')).'</a>';
 954                  $output = $link;
 955      }
 956          if ($return) {
 957              return $output;
 958          } else {
 959              echo $output;
 960          }
 961  }
 962  
 963  /**
 964  * This function takes care of the display of the up and down icon
 965  *
 966  * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
 967  * @param $id is the id of the item we want to display the icons for
 968  * @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)
 969  *          The key of this $list array is the id of the item.
 970  *
 971  * @return
 972  *
 973  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
 974  * @version february 2006, dokeos 1.8
 975  */
 976  function display_up_down_icon($content, $id, $list) {
 977      $id = strval(intval($id));
 978      $total_items=count($list);
 979      $position = 0;
 980      $internal_counter=0;
 981  
 982      if(is_array($list)) {
 983          foreach ($list as $key=>$listitem) {
 984              $internal_counter++;
 985              if ($id==$key) {
 986                  $position=$internal_counter;
 987              }
 988          }
 989      }
 990      if ($position>1) {
 991          $return_value='<td width="5%" align="center"><a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&amp;direction=up&amp;content='.$content.'&amp;forumcategory='.Security::remove_XSS($_GET['forumcategory']).'&amp;id='.$id.'" title="'.get_lang('MoveUp').'">'.Display::return_icon('up.gif',get_lang('MoveUp')).'</a></td>';
 992      } else {
 993          $return_value=Display::return_icon('up_na.gif','-');
 994      }
 995  
 996      if ($position<$total_items) {
 997          $return_value.='<td width="5%" align="center"><a href="'.api_get_self().'?'.api_get_cidreq().'&action=move&amp;direction=down&amp;content='.$content.'&amp;forumcategory='.Security::remove_XSS($_GET['forumcategory']).'&amp;id='.$id.'" title="'.get_lang('MoveDown').'" >'.Display::return_icon('down.gif',get_lang('MoveDown')).'</a></td>';
 998      } else {
 999  
1000         $return_value.= '<td width="5%" align="center">'.Display::return_icon('down_na.gif','-').'</td>';
1001      }
1002      echo $return_value;
1003  }
1004  
1005  
1006  
1007  
1008  /**
1009  * This function changes the visibility in the database (item_property)
1010  *
1011  * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
1012  * @param $id the id of the content we want to make invisible
1013  * @param $target_visibility what is the current status of the visibility (0 = invisible, 1 = visible)
1014  *
1015  * @todo change the get parameter so that it matches the tool constants.
1016  * @todo check if api_item_property_update returns true or false => returnmessage depends on it.
1017  * @todo move to itemmanager
1018  *
1019  * @return
1020  *
1021  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1022  * @version february 2006, dokeos 1.8
1023  */
1024  function change_visibility($content, $id, $target_visibility) {
1025      global $_course;
1026      $constants=array('forumcategory'=>TOOL_FORUM_CATEGORY, 'forum'=>TOOL_FORUM, 'thread'=>TOOL_FORUM_THREAD);
1027      api_item_property_update($_course,$constants[$content],$id,$target_visibility,api_get_user_id()); // note: check if this returns true or false => returnmessage depends on it.
1028      if ($target_visibility=='visible') {
1029          handle_mail_cue($content, $id);
1030      }
1031      return get_lang('VisibilityChanged');
1032  }
1033  
1034  
1035  /**
1036  * This function changes the lock status in the database
1037  *
1038  * @param $content what is it that we want to (un)lock: forum category, forum, thread, post
1039  * @param $id the id of the content we want to (un)lock
1040  * @param $action do we lock (=>locked value in db = 1) or unlock (=> locked value in db = 0)
1041  * @return string, language variable
1042  *
1043  * @todo move to itemmanager
1044  *
1045  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1046  * @version february 2006, dokeos 1.8
1047  */
1048  function change_lock_status($content, $id, $action) {
1049      global $table_categories;
1050      global $table_forums;
1051      global $table_threads;
1052      global $table_posts;
1053  
1054      // Determine the relevant table
1055      if ($content=='forumcategory') {
1056          $table=$table_categories;
1057          $id_field='cat_id';
1058      } elseif ($content=='forum') {
1059          $table=$table_forums;
1060          $id_field='forum_id';
1061      } elseif ($content=='thread') {
1062          $table=$table_threads;
1063          $id_field='thread_id';
1064      } else {
1065          return get_lang('Error');
1066      }
1067  
1068      // Determine what we are doing => defines the value for the database and the return message
1069      if ($action=='lock') {
1070          $db_locked=1;
1071          $return_message=get_lang('Locked');
1072      } elseif ($action=='unlock') {
1073          $db_locked=0;
1074          $return_message=get_lang('Unlocked');
1075      } else {
1076          return get_lang('Error');
1077      }
1078  
1079      // Doing the change in the database
1080      $sql="UPDATE $table SET locked='".Database::escape_string($db_locked)."' WHERE $id_field='".Database::escape_string($id)."'";
1081      if (Database::query($sql,__FILE__,__LINE__)) {
1082          return $return_message;
1083      } else {
1084          return get_lang('Error');
1085      }
1086  }
1087  
1088  
1089  /**
1090  * This function moves a forum or a forum category up or down
1091  *
1092  * @param $content what is it that we want to make (in)visible: forum category, forum, thread, post
1093  * @param $direction do we want to move it up or down.
1094  * @param $id the id of the content we want to make invisible
1095  * @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
1096  *         the item_property table but does have one in the forum table.
1097  * @return
1098  *
1099  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1100  * @version february 2006, dokeos 1.8
1101  */
1102  function move_up_down($content, $direction, $id) {
1103      global $table_categories;
1104      global $table_forums;
1105      global $table_item_property;
1106  
1107      // Determine which field holds the sort order
1108      if ($content=='forumcategory') {
1109          $table=$table_categories;
1110          $sort_column='cat_order';
1111          $id_column='cat_id';
1112          $sort_column='cat_order';
1113      } elseif ($content=='forum') {
1114          $table=$table_forums;
1115          $sort_column='forum_order';
1116          $id_column='forum_id';
1117          $sort_column='forum_order';
1118          // we also need the forum_category of this forum
1119          $sql="SELECT forum_category FROM $table_forums WHERE forum_id=".Database::escape_string($id);
1120          $result=Database::query($sql,__FILE__,__LINE__);
1121          $row=Database::fetch_array($result);
1122          $forum_category=$row['forum_category'];
1123      } else {
1124          return get_lang('Error');
1125      }
1126  
1127      // determine if need to sort ascending or descending
1128      if ($direction=='down') {
1129          $sort_direction='ASC';
1130      } elseif ($direction=='up') {
1131          $sort_direction='DESC';
1132      } else {
1133          return get_lang('Error');
1134      }
1135  
1136      // The SQL statement
1137      if ($content=='forumcategory') {
1138          $sql="SELECT * FROM".$table_categories." forum_categories, ".$table_item_property." item_properties
1139                      WHERE forum_categories.cat_id=item_properties.ref
1140                      AND item_properties.tool='".TOOL_FORUM_CATEGORY."'
1141                      ORDER BY forum_categories.cat_order $sort_direction";
1142      }
1143      if ($content=='forum') {
1144          $sql="SELECT * FROM".$table." WHERE forum_category='".Database::escape_string($forum_category)."' ORDER BY forum_order $sort_direction";
1145      }
1146      // echo $sql.'<br />';
1147      // finding the items that need to be switched
1148      $result=Database::query($sql,__FILE__,__LINE__);
1149      $found=false;
1150      while ($row=Database::fetch_array($result)) {
1151          //echo $row[$id_column].'-';
1152          if ($found==true) {
1153              $next_id=$row[$id_column];
1154              $next_sort=$row[$sort_column];
1155              $found=false;
1156          }
1157          if($id==$row[$id_column]) {
1158              $this_id=$id;
1159              $this_sort=$row[$sort_column];
1160              $found=true;
1161          }
1162      }
1163  
1164      // Committing the switch
1165      // we do an extra check if we do not have illegal values. If your remove this if statment you will
1166      // be able to mess with the sorting by refreshing the page over and over again.
1167      if ($this_sort<>'' && $next_sort<>'' && $next_id<>'' && $this_id<>'') {
1168          $sql_update1="UPDATE $table SET $sort_column='".Database::escape_string($this_sort)."' WHERE $id_column='".Database::escape_string($next_id)."'";
1169          $sql_update2="UPDATE $table SET $sort_column='".Database::escape_string($next_sort)."' WHERE $id_column='".Database::escape_string($this_id)."'";
1170          Database::query($sql_update1,__FILE__,__LINE__);
1171          Database::query($sql_update2,__FILE__,__LINE__);
1172      }
1173  
1174      return get_lang(ucfirst($content).'Moved');
1175  }
1176  
1177  
1178  /**
1179  * This function returns a piece of html code that make the links grey (=invisible for the student)
1180  *
1181  * @param boolean 0/1: 0 = invisible, 1 = visible
1182  * @return string
1183  *
1184  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1185  * @version february 2006, dokeos 1.8
1186  */
1187  function class_visible_invisible($current_visibility_status) {
1188      if ($current_visibility_status=='0') {
1189          return "class='invisible'";
1190      }
1191  }
1192  
1193  /**
1194  * Retrieve all the information off the forum categories (or one specific) for the current course.
1195  * The categories are sorted according to their sorting order (cat_order
1196  *
1197  * @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.
1198  * @return an array containing all the information about all the forum categories
1199  *
1200  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1201  * @version february 2006, dokeos 1.8
1202  */
1203  function get_forum_categories($id='') {
1204      $table_categories        = Database :: get_course_table(TABLE_FORUM_CATEGORY);
1205      $table_item_property    = Database :: get_course_table(TABLE_ITEM_PROPERTY);
1206      $forum_categories_list = array();
1207  
1208      //condition for the session
1209      $session_id = api_get_session_id();
1210      $condition_session = api_get_session_condition($session_id, true, true);
1211  
1212      if ($id == '') {
1213          $sql="SELECT * FROM".$table_categories." forum_categories, ".$table_item_property." item_properties
1214                      WHERE forum_categories.cat_id=item_properties.ref
1215                      AND item_properties.visibility=1
1216                      AND item_properties.tool='".TOOL_FORUM_CATEGORY."' $condition_session
1217                      ORDER BY forum_categories.cat_order ASC";
1218          if (is_allowed_to_edit()) {
1219              $sql="SELECT * FROM".$table_categories." forum_categories, ".$table_item_property." item_properties
1220                      WHERE forum_categories.cat_id=item_properties.ref
1221                      AND item_properties.visibility<>2
1222                      AND item_properties.tool='".TOOL_FORUM_CATEGORY."' $condition_session
1223                      ORDER BY forum_categories.cat_order ASC";
1224          }
1225      } else {
1226          $sql="SELECT * FROM".$table_categories." forum_categories, ".$table_item_property." item_properties
1227                  WHERE forum_categories.cat_id=item_properties.ref
1228                  AND item_properties.tool='".TOOL_FORUM_CATEGORY."'
1229                  AND forum_categories.cat_id='".Database::escape_string($id)."' $condition_session
1230                  ORDER BY forum_categories.cat_order ASC";
1231      }
1232      $result=Database::query($sql,__FILE__,__LINE__);
1233      while ($row=Database::fetch_array($result)) {
1234          if ($id=='') {
1235              $forum_categories_list[$row['cat_id']]=$row;
1236          } else {
1237              $forum_categories_list=$row;
1238          }
1239      }
1240      return $forum_categories_list;
1241  }
1242  
1243  /**
1244  * This function retrieves all the fora in a given forum category
1245  *
1246  * @param integer $cat_id the id of the forum category
1247  * @return an array containing all the information about the forums (regardless of their category)
1248  *
1249  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1250  * @version february 2006, dokeos 1.8
1251  */
1252  function get_forums_in_category($cat_id)
1253  {
1254      global $table_forums;
1255      global $table_item_property;
1256      $forum_list=array();
1257      $sql="SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
1258                  WHERE forum.forum_category='".Database::escape_string($cat_id)."'
1259                  AND forum.forum_id=item_properties.ref
1260                  AND item_properties.visibility=1
1261                  AND item_properties.tool='".TOOL_FORUM."'
1262                  ORDER BY forum.forum_order ASC";
1263      if (is_allowed_to_edit()) {
1264          $sql="SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
1265                  WHERE forum.forum_category='".Database::escape_string($cat_id)."'
1266                  AND forum.forum_id=item_properties.ref
1267                  AND item_properties.visibility<>2
1268                  AND item_properties.tool='".TOOL_FORUM."'
1269                  ORDER BY forum_order ASC";
1270      }
1271      $result=Database::query($sql,__FILE__,__LINE__);
1272      while ($row=Database::fetch_array($result)) {
1273          $forum_list[$row['forum_id']]=$row;
1274      }
1275      return $forum_list;
1276  }
1277  /**
1278  * Retrieve all the forums (regardless of their category) or of only one. The forums are sorted according to the forum_order.
1279  * Since it does not take the forum category into account there probably will be two or more forums that have forum_order=1, ...
1280  *
1281  * @return an array containing all the information about the forums (regardless of their category)
1282  * @todo check $sql4 because this one really looks fishy.
1283  *
1284  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1285  * @version february 2006, dokeos 1.8
1286  */
1287  function get_forums($id='') {
1288      global $table_forums;
1289      global $table_threads;
1290      global $table_posts;
1291      global $table_item_property;
1292      global $table_users;
1293  
1294      // **************** GETTING ALL THE FORUMS ************************* //
1295  
1296      //condition for the session
1297      $session_id = api_get_session_id();
1298      $condition_session = api_get_session_condition($session_id, true, true);
1299  
1300      $forum_list = array();
1301      if ($id=='') {
1302          //-------------- Student -----------------//
1303          // select all the forum information of all forums (that are visible to students)
1304          $sql="SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
1305                      WHERE forum.forum_id=item_properties.ref
1306                      AND item_properties.visibility=1
1307                      AND item_properties.tool='".TOOL_FORUM."'
1308                      $condition_session
1309                      ORDER BY forum.forum_order ASC";
1310          // select the number of threads of the forums (only the threads that are visible)
1311          $sql2="SELECT count(*) AS number_of_threads, threads.forum_id FROM $table_threads threads, ".$table_item_property." item_properties
1312                          WHERE threads.thread_id=item_properties.ref
1313                          AND item_properties.visibility=1
1314                          AND item_properties.tool='".TOOL_FORUM_THREAD."'
1315                          GROUP BY threads.forum_id";
1316          // select the number of posts of the forum (post that are visible and that are in a thread that is visible)
1317          $sql3="SELECT count(*) AS number_of_posts, posts.forum_id FROM $table_posts posts, $table_threads threads, ".$table_item_property." item_properties
1318                  WHERE posts.visible=1
1319                  AND posts.thread_id=threads.thread_id
1320                  AND threads.thread_id=item_properties.ref
1321                  AND item_properties.visibility=1
1322                  AND item_properties.tool='".TOOL_FORUM_THREAD."'
1323                  GROUP BY threads.forum_id";
1324  
1325          //-------------- Course Admin  -----------------//
1326          if (is_allowed_to_edit()) {
1327              // select all the forum information of all forums (that are not deleted)
1328              $sql="SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
1329                              WHERE forum.forum_id=item_properties.ref
1330                              AND item_properties.visibility<>2
1331                              AND item_properties.tool='".TOOL_FORUM."'
1332                              $condition_session
1333                              ORDER BY forum_order ASC";
1334              //echo $sql.'<hr>';
1335              // select the number of threads of the forums (only the threads that are not deleted)
1336              $sql2="SELECT count(*) AS number_of_threads, threads.forum_id FROM $table_threads threads, ".$table_item_property." item_properties
1337                              WHERE threads.thread_id=item_properties.ref
1338                              AND item_properties.visibility<>2
1339                              AND item_properties.tool='".TOOL_FORUM_THREAD."'
1340                              GROUP BY threads.forum_id";
1341              //echo $sql2.'<hr>';
1342              // select the number of posts of the forum
1343              $sql3="SELECT count(*) AS number_of_posts, posts.forum_id FROM $table_posts posts, $table_threads threads, ".$table_item_property." item_properties
1344              WHERE posts.thread_id=threads.thread_id
1345              AND threads.thread_id=item_properties.ref
1346              AND item_properties.visibility=1
1347              AND item_properties.tool='".TOOL_FORUM_THREAD."'
1348              GROUP BY threads.forum_id";
1349              //echo $sql3.'<hr>';
1350          }
1351  
1352  
1353      }
1354      // **************** GETTING ONE SPECIFIC FORUM ************************* //
1355      // 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
1356      // 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
1357      // when editing a forum (and for the moment it is the only place where we use this part of the function)
1358      else {
1359          // select all the forum information of the given forum (that is not deleted)
1360          $sql="SELECT * FROM ".$table_forums." forum , ".$table_item_property." item_properties
1361                              WHERE forum.forum_id=item_properties.ref
1362                              AND forum_id='".Database::escape_string($id)."'
1363                              AND item_properties.visibility<>2
1364                              AND item_properties.tool='".TOOL_FORUM."'
1365                              $condition_session
1366                              ORDER BY forum_order ASC";
1367          // select the number of threads of the forum
1368          $sql2="SELECT count(*) AS number_of_threads, forum_id FROM $table_threads WHERE forum_id=".Database::escape_string($id)." GROUP BY forum_id";
1369          // select the number of posts of the forum
1370          $sql3="SELECT count(*) AS number_of_posts, forum_id FROM $table_posts WHERE forum_id=".Database::escape_string($id)." GROUP BY forum_id";
1371          // select the last post and the poster (note: this is probably no longer needed)
1372          $sql4="SELECT  post.post_id, post.forum_id, post.poster_id, post.poster_name, post.post_date, users.lastname, users.firstname
1373                      FROM $table_posts post, $table_users users
1374                      WHERE forum_id=".Database::escape_string($id)."
1375                      AND post.poster_id=users.user_id
1376                      GROUP BY post.forum_id
1377                      ORDER BY post.post_id ASC";
1378      }
1379      // handling all the forum information
1380      $result=Database::query($sql,__FILE__,__LINE__);
1381      while ($row=Database::fetch_array($result)) {
1382          if ($id=='') {
1383              $forum_list[$row['forum_id']]=$row;
1384          } else {
1385              $forum_list=$row;
1386          }
1387      }
1388  
1389      // handling the threadcount information
1390      $result2=Database::query($sql2,__FILE__,__LINE__);
1391      while ($row2=Database::fetch_array($result2)) {
1392          if ($id=='') {
1393              $forum_list[$row2['forum_id']]['number_of_threads']=$row2['number_of_threads'];
1394          } else {
1395              $forum_list['number_of_threads']=$row2['number_of_threads'];;
1396          }
1397      }
1398      // handling the postcount information
1399      $result3=Database::query($sql3,__FILE__,__LINE__);
1400      while ($row3=Database::fetch_array($result3)) {
1401          if ($id=='') {
1402              if (array_key_exists($row3['forum_id'],$forum_list)) {// this is needed because sql3 takes also the deleted forums into account
1403                  $forum_list[$row3['forum_id']]['number_of_posts']=$row3['number_of_posts'];
1404              }
1405          } else {
1406              $forum_list['number_of_posts']=$row3['number_of_posts'];
1407          }
1408      }
1409  
1410      // finding the last post information (last_post_id, last_poster_id, last_post_date, last_poster_name, last_poster_lastname, last_poster_firstname)
1411      if ($id=='') {
1412          if(is_array($forum_list)) {
1413              foreach ($forum_list as $key=>$value) {
1414                  $last_post_info_of_forum=get_last_post_information($key,is_allowed_to_edit());
1415                  $forum_list[$key]['last_post_id']=$last_post_info_of_forum['last_post_id'];
1416                  $forum_list[$key]['last_poster_id']=$last_post_info_of_forum['last_poster_id'];
1417                  $forum_list[$key]['last_post_date']=$last_post_info_of_forum['last_post_date'];
1418                  $forum_list[$key]['last_poster_name']=$last_post_info_of_forum['last_poster_name'];
1419                  $forum_list[$key]['last_poster_lastname']=$last_post_info_of_forum['last_poster_lastname'];
1420                  $forum_list[$key]['last_poster_firstname']=$last_post_info_of_forum['last_poster_firstname'];
1421              }
1422          } else {
1423              $forum_list = array();
1424          }
1425      } else {
1426          $last_post_info_of_forum=get_last_post_information($id,is_allowed_to_edit());
1427          $forum_list['last_post_id']=$last_post_info_of_forum['last_post_id'];
1428          $forum_list['last_poster_id']=$last_post_info_of_forum['last_poster_id'];
1429          $forum_list['last_post_date']=$last_post_info_of_forum['last_post_date'];
1430          $forum_list['last_poster_name']=$last_post_info_of_forum['last_poster_name'];
1431          $forum_list['last_poster_lastname']=$last_post_info_of_forum['last_poster_lastname'];
1432          $forum_list['last_poster_firstname']=$last_post_info_of_forum['last_poster_firstname'];
1433      }
1434      return $forum_list;
1435  }
1436  
1437  /**
1438  * This functions gets all the last post information of a certain forum
1439  *
1440  * @param $forum_id the id of the forum we want to know the last post information of.
1441  * @param $show_invisibles
1442  * @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)
1443  *
1444  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1445  * @version february 2006, dokeos 1.8
1446  */
1447  function get_last_post_information($forum_id, $show_invisibles=false) {
1448      global $table_forums;
1449      global $table_threads;
1450      global $table_posts;
1451      global $table_item_property;
1452      global $table_users;
1453  
1454      $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
1455                  FROM $table_posts post, $table_users users, $table_item_property thread_properties,  $table_item_property forum_properties
1456                  WHERE post.forum_id=".Database::escape_string($forum_id)."
1457                  AND post.poster_id=users.user_id
1458                  AND post.thread_id=thread_properties.ref
1459                  AND thread_properties.tool='".TOOL_FORUM_THREAD."'
1460                  AND post.forum_id=forum_properties.ref
1461                  AND forum_properties.tool='".TOOL_FORUM."'
1462                  ORDER BY post.post_id DESC";
1463      $result=Database::query($sql,__FILE__,__LINE__);
1464      if ($show_invisibles==true) {
1465          $row=Database::fetch_array($result);
1466          $return_array['last_post_id']=$row['post_id'];
1467          $return_array['last_poster_id']=$row['poster_id'];
1468          $return_array['last_post_date']=$row['post_date'];
1469          $return_array['last_poster_name']=$row['poster_name'];
1470          $return_array['last_poster_lastname']=$row['lastname'];
1471          $return_array['last_poster_firstname']=$row['firstname'];
1472          return $return_array;
1473      } else {
1474          // 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)
1475          while ($row=Database::fetch_array($result)) {
1476              if ($row['visible']=='1' AND $row['thread_visibility']=='1' AND $row['forum_visibility']=='1') {
1477                  $return_array['last_post_id']=$row['post_id'];
1478                  $return_array['last_poster_id']=$row['poster_id'];
1479                  $return_array['last_post_date']=$row['post_date'];
1480                  $return_array['last_poster_name']=$row['poster_name'];
1481                  $return_array['last_poster_lastname']=$row['lastname'];
1482                  $return_array['last_poster_firstname']=$row['firstname'];
1483                  return $return_array;
1484              }
1485          }
1486      }
1487  }
1488  
1489  /**
1490  * Retrieve all the threads of a given forum
1491  *
1492  * @param
1493  * @return an array containing all the information about the threads
1494  *
1495  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1496  * @version february 2006, dokeos 1.8
1497  */
1498  function get_threads($forum_id) {
1499      global $table_item_property;
1500      global $table_threads;
1501      global $table_posts;
1502      global $table_users;
1503      $thread_list=array();
1504      // important note:     it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1505      //                    because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1506      //                     since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1507      //                    This is why it is added to the end of the field selection
1508  
1509  
1510      $sql = "SELECT thread.*, item_properties.*, users.firstname, users.lastname, users.user_id,
1511      post.post_id, post.post_title, post.post_text, post.forum_id, post.poster_id, post.poster_name, post.post_date, post.post_notification, post.post_parent_id, post.visible,
1512                  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
1513              FROM $table_threads thread
1514              INNER JOIN $table_item_property item_properties
1515                  ON thread.thread_id=item_properties.ref
1516                  AND item_properties.visibility='1'
1517                  AND item_properties.tool='".TABLE_FORUM_THREAD."'
1518              LEFT JOIN $table_users users
1519                  ON thread.thread_poster_id=users.user_id
1520              LEFT JOIN $table_posts post
1521                  ON thread.thread_last_post = post.post_id
1522              LEFT JOIN $table_users last_poster_users
1523                  ON post.poster_id= last_poster_users.user_id
1524              WHERE thread.forum_id='".Database::escape_string($forum_id)."'
1525              ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1526      if (is_allowed_to_edit()) {
1527          // important note:     it might seem a little bit awkward that we have 'thread.locked as locked' in the sql statement
1528          //                    because we also have thread.* in it. This is because thread has a field locked and post also has the same field
1529          //                     since we are merging these we would have the post.locked value but in fact we want the thread.locked value
1530          //                    This is why it is added to the end of the field selection
1531          $sql = "SELECT thread.*, item_properties.*, users.firstname, users.lastname, users.user_id,
1532        post.post_id, post.post_title, post.post_text, post.forum_id, post.poster_id, post.poster_name, post.post_date, post.post_notification, post.post_parent_id, post.visible,
1533                      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
1534                  FROM $table_threads thread
1535                  INNER JOIN $table_item_property item_properties
1536                      ON thread.thread_id=item_properties.ref
1537                      AND item_properties.visibility<>2
1538                      AND item_properties.tool='".TABLE_FORUM_THREAD."'
1539                  LEFT JOIN $table_users users
1540                      ON thread.thread_poster_id=users.user_id
1541                  LEFT JOIN $table_posts post
1542                      ON thread.thread_last_post = post.post_id
1543                  LEFT JOIN $table_users last_poster_users
1544                      ON post.poster_id= last_poster_users.user_id
1545                  WHERE thread.forum_id='".Database::escape_string($forum_id)."'
1546                  ORDER BY thread.thread_sticky DESC, thread.thread_date DESC";
1547      }
1548      $result=Database::query($sql, __FILE__, __LINE__);
1549      while ( $row=Database::fetch_array($result,'ASSOC') ) {
1550          $thread_list[]=$row;
1551      }
1552      return $thread_list;
1553  }
1554  
1555  /**
1556  * Retrieve all posts of a given thread
1557  *
1558  * @return an array containing all the information about the posts of a given thread
1559  *
1560  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1561  * @version february 2006, dokeos 1.8
1562  */
1563  function get_posts($thread_id) {
1564      global $table_posts;
1565      global $table_users;
1566  
1567      // note: change these SQL so that only the relevant fields of the user table are used
1568      if (api_is_allowed_to_edit(null,true)) {
1569          $sql = "SELECT * FROM $table_posts posts
1570                  LEFT JOIN  $table_users users
1571                      ON posts.poster_id=users.user_id
1572                  WHERE posts.thread_id='".Database::escape_string($thread_id)."'
1573                  ORDER BY posts.post_id ASC";
1574      } else {
1575          // students can only se the posts that are approved (posts.visible='1')
1576          $sql = "SELECT * FROM $table_posts posts
1577                  LEFT JOIN  $table_users users
1578                      ON posts.poster_id=users.user_id
1579                  WHERE posts.thread_id='".Database::escape_string($thread_id)."'
1580                  AND posts.visible='1'
1581                  ORDER BY posts.post_id ASC";
1582      }
1583      $result=Database::query($sql, __FILE__, __LINE__);
1584      while ($row=Database::fetch_array($result)) {
1585          $post_list[]=$row;
1586      }
1587      return $post_list;
1588  }
1589  
1590  /**
1591  * This function return the html syntax for the image
1592  *
1593  * @param $image_url The url of the image (absolute or relative)
1594  * @param $alt The alt text (when the images cannot be displayed). http://www.w3.org/TR/html4/struct/objects.html#adef-alt
1595  * @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
1596  *
1597  * @todo this is the same as the Display::xxx function, so it can be removed => all calls have to be changed also
1598  *
1599  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1600  * @version february 2006, dokeos 1.8
1601  */
1602  function icon($image_url,$alt='',$title='') {
1603      if ($title=='') {
1604          $title=$alt;
1605      }
1606      return '<img src="'.$image_url.'" alt="'.$alt.'" title="'.$title.'" />';
1607  }
1608  
1609  
1610  
1611  
1612  
1613  
1614  /**************************************************************************
1615                      NEW TOPIC FUNCTIONS
1616  **************************************************************************/
1617  
1618  /**
1619  * This function retrieves all the information of a post
1620  *
1621  * @param $forum_id integer that indicates the forum
1622  * @return array returns
1623  *
1624  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1625  * @version february 2006, dokeos 1.8
1626  */
1627  function get_post_information($post_id) {
1628      global $table_posts;
1629      global $table_users;
1630  
1631      $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)."'";
1632      $result=Database::query($sql, __FILE__, __LINE__);
1633      $row=Database::fetch_array($result);
1634      return $row;
1635  }
1636  
1637  
1638  /**
1639  * This function retrieves all the information of a thread
1640  *
1641  * @param $forum_id integer that indicates the forum
1642  * @return array returns
1643  *
1644  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1645  * @version february 2006, dokeos 1.8
1646  */
1647  function get_thread_information($thread_id) {
1648      global $table_threads;
1649      global $table_item_property;
1650  
1651      $sql="SELECT * FROM ".$table_threads." threads, ".$table_item_property." item_properties
1652              WHERE item_properties.tool='".TOOL_FORUM_THREAD."'
1653              AND item_properties.ref='".Database::escape_string($thread_id)."'
1654              AND threads.thread_id='".Database::escape_string($thread_id)."'";
1655      $result=Database::query($sql, __FILE__, __LINE__);
1656      $row=Database::fetch_array($result);
1657      return $row;
1658  }
1659  
1660  /**
1661  * This function retrieves forum thread users details
1662  * @param     int Thread ID
1663  * @param    string    Course DB name (optional)
1664  * @return    array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1665  * @author Christian Fasanando <christian.fasanando@dokeos.com>,
1666  * @version octubre 2008, dokeos 1.8
1667  */
1668  
1669  function get_thread_users_details($thread_id, $db_name = null) {
1670      $t_posts = Database :: get_course_table(TABLE_FORUM_POST, (empty($db_name)?null:$db_name));
1671      $t_users = Database :: get_main_table(TABLE_MAIN_USER);
1672      $t_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1673      $sql = "SELECT DISTINCT user.user_id, user.lastname, user.firstname, thread_id
1674                FROM $t_posts , $t_users user, $t_course_user course_user
1675                WHERE poster_id = user.user_id
1676                AND user.user_id = course_user.user_id
1677                AND thread_id = '".Database::escape_string($thread_id)."'
1678                AND course_user.status NOT IN('1')
1679                AND course_code = '".api_get_course_id()."'";
1680  
1681      $result = Database::query($sql, __FILE__, __LINE__);
1682      return $result;
1683  }
1684  
1685  /**
1686  * This function retrieves forum thread users qualify
1687  * @param     int Thread ID
1688  * @param    string    Course DB name (optional)
1689  * @return    array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1690  * @author Jhon Hinojosa<jhon.hinojosa@dokeos.com>,
1691  * @version octubre 2008, dokeos 1.8
1692  */
1693  
1694  function get_thread_users_qualify($thread_id, $db_name = null) {
1695      $t_posts = Database :: get_course_table(TABLE_FORUM_POST, (empty($db_name)?null:$db_name));
1696      $t_qualify = Database :: get_course_table(TABLE_FORUM_THREAD_QUALIFY, (empty($db_name)?null:$db_name));
1697      $t_users = Database :: get_main_table(TABLE_MAIN_USER);
1698      $t_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1699  
1700    $sql = "SELECT post.poster_id, user.lastname, user.firstname, post.thread_id,user.user_id,qualify.qualify
1701                          FROM $t_posts post,
1702                               $t_qualify qualify,
1703                               $t_users user,
1704                               $t_course_user course_user
1705                          WHERE
1706                               post.poster_id = user.user_id
1707                               AND post.poster_id = qualify.user_id
1708                               AND user.user_id = course_user.user_id
1709                               AND qualify.thread_id = '".Database::escape_string($thread_id)."'
1710                               AND course_user.status not in('1')
1711                               AND course_code = '".api_get_course_id()."'
1712                          GROUP BY post.poster_id ";
1713      $result = Database::query($sql, __FILE__, __LINE__);
1714      return $result;
1715  }
1716  
1717  /**
1718  * This function retrieves forum thread users not qualify
1719  * @param     int Thread ID
1720  * @param    string    Course DB name (optional)
1721  * @return    array Array of type ([user_id=>w,lastname=>x,firstname=>y,thread_id=>z],[])
1722  * @author Jhon Hinojosa<jhon.hinojosa@dokeos.com>,
1723  * @version octubre 2008, dokeos 1.8
1724  */
1725  
1726  function get_thread_users_not_qualify($thread_id, $db_name = null) {
1727      $t_posts = Database :: get_course_table(TABLE_FORUM_POST, (empty($db_name)?null:$db_name));
1728      $t_qualify = Database :: get_course_table(TABLE_FORUM_THREAD_QUALIFY, (empty($db_name)?null:$db_name));
1729      $t_users = Database :: get_main_table(TABLE_MAIN_USER);
1730      $t_course_user = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
1731  
1732        $sql1 = "select user_id FROM  $t_qualify WHERE thread_id = '".$thread_id."'";
1733      $result1 = Database::query($sql1,__FILE__,__LINE__);
1734      $cad='';
1735      while ($row=Database::fetch_array($result1)) {
1736          $cad .= $row['user_id'].',';
1737      }
1738      if($cad=='') {
1739          $cad='0';
1740      } else  {
1741          $cad=substr($cad,0,strlen($cad)-1);
1742      }
1743      $sql = "SELECT DISTINCT user.user_id, user.lastname, user.firstname, post.thread_id
1744                FROM $t_posts post, $t_users user,$t_course_user course_user
1745                WHERE post.poster_id = user.user_id
1746                AND user.user_id NOT IN (".$cad.")
1747                AND user.user_id = course_user.user_id
1748                AND post.thread_id = '".Database::escape_string($thread_id)."'
1749                AND course_user.status not in('1')
1750                AND course_code = '".api_get_course_id()."'";
1751  
1752      $result = Database::query($sql, __FILE__, __LINE__);
1753      return $result;
1754  }
1755  
1756  
1757  /**
1758  * This function retrieves all the information of a given forum_id
1759  *
1760  * @param $forum_id integer that indicates the forum
1761  * @return array returns
1762  *
1763  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1764  * @version february 2006, dokeos 1.8
1765  *
1766  * @deprecated this functionality is now moved to get_forums($forum_id)
1767  */
1768  function get_forum_information($forum_id) {
1769      global $table_forums;
1770      global $table_item_property;
1771  
1772      $sql="SELECT * FROM ".$table_forums." forums, ".$table_item_property." item_properties
1773              WHERE item_properties.tool='".TOOL_FORUM."'
1774              AND item_properties.ref='".Database::escape_string($forum_id)."'
1775              AND forums.forum_id='".Database::escape_string($forum_id)."'";
1776      $result=Database::query($sql, __FILE__, __LINE__);
1777      $row=Database::fetch_array($result);
1778      $row['approval_direct_post'] = 0; // we can't anymore change this option, so it should always be activated
1779      return $row;
1780  }
1781  
1782  /**
1783  * This function retrieves all the information of a given forumcategory id
1784  *
1785  * @param $forum_id integer that indicates the forum
1786  * @return array returns
1787  *
1788  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1789  * @version february 2006, dokeos 1.8
1790  */
1791  function get_forumcategory_information($cat_id) {
1792      global $table_categories;
1793      global $table_item_property;
1794  
1795      $sql="SELECT * FROM ".$table_categories." forumcategories, ".$table_item_property." item_properties
1796              WHERE item_properties.tool='".TOOL_FORUM_CATEGORY."'
1797              AND item_properties.ref='".Database::escape_string($cat_id)."'
1798              AND forumcategories.cat_id='".Database::escape_string($cat_id)."'";
1799      $result=Database::query($sql, __FILE__, __LINE__);
1800      $row=Database::fetch_array($result);
1801      return $row;
1802  }
1803  
1804  /**
1805  * This function counts the number of forums inside a given category
1806  *
1807  * @param $cat_id the id of the forum category
1808  * @todo an additional parameter that takes the visibility into account. For instance $countinvisible=0 would return the number
1809  *         of visible forums, $countinvisible=1 would return the number of visible and invisible forums
1810  * @return int the number of forums inside the given category
1811  *
1812  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1813  * @version february 2006, dokeos 1.8
1814  */
1815  function count_number_of_forums_in_category($cat_id) {
1816      global $table_forums;
1817  
1818      $sql="SELECT count(*) AS number_of_forums FROM ".$table_forums." WHERE forum_category='".Database::escape_string($cat_id)."'";
1819      $result=Database::query($sql, __FILE__, __LINE__);
1820      $row=Database::fetch_array($result);
1821      return $row['number_of_forums'];
1822  }
1823  
1824  /**
1825  * This function stores a new thread. This is done through an entry in the forum_thread table AND
1826  * in the forum_post table because. The threads are also stored in the item_property table. (forum posts are not (yet))
1827  *
1828  * @param
1829  * @return
1830  *
1831  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1832  * @version february 2006, dokeos 1.8
1833  */
1834  function store_thread($values) {
1835      global $table_threads;
1836      global $table_posts;
1837      global $_user;
1838      global $_course;
1839      global $current_forum;
1840      global $origin;
1841      global $forum_table_attachment;
1842      $gradebook=Security::remove_XSS($_GET['gradebook']);
1843  
1844      $upload_ok=1;
1845      $has_attachment=false;
1846  
1847      if(!empty($_FILES['user_upload']['name'])) {
1848          $upload_ok = process_uploaded_file($_FILES['user_upload']);
1849          $has_attachment=true;
1850      }
1851      if($upload_ok) {
1852  
1853          $post_date=date('Y-m-d H:i:s');
1854  
1855          if ($current_forum['approval_direct_post']=='1' AND !api_is_allowed_to_edit(null,true)) {
1856              $visible=0; // the post is not approved yet.
1857          } else {
1858              $visible=1;
1859          }
1860  
1861          $clean_post_title=Database::escape_string(Security::remove_XSS($values['post_title']));
1862  
1863          // We first store an entry in the forum_thread table because the thread_id is used in the forum_post table
1864          $sql="INSERT INTO $table_threads (thread_title, forum_id, thread_poster_id, thread_poster_name, thread_date, thread_sticky,thread_title_qualify,thread_qualify_max,thread_weight,session_id)
1865                  VALUES ('".$clean_post_title."',
1866                          '".Database::escape_string($values['forum_id'])."',
1867                          '".Database::escape_string($_user['user_id'])."',
1868                          '".Database::escape_string(isset($values['poster_name'])?$values['poster_name']:null)."',
1869                          '".Database::escape_string($post_date)."',
1870                          '".Database::escape_string(isset($values['thread_sticky'])?$values['thread_sticky']:null)."'," .
1871                          "'".Database::escape_string($values['calification_notebook_title'])."'," .
1872                          "'".Database::escape_string($values['numeric_calification'])."'," .
1873                          "'".Database::escape_string($values['weight_calification'])."'," .
1874                          "'".api_get_session_id()."')";
1875          $result=Database::query($sql, __LINE__, __FILE__);
1876          $last_thread_id=Database::insert_id();
1877  
1878          //add option gradebook qualify
1879  
1880          if(isset($values['thread_qualify_gradebook']) && 1==$values['thread_qualify_gradebook']) {
1881              //add function gradebook
1882              $coursecode=api_get_course_id();
1883              $resourcetype=5;
1884              $resourceid=$last_thread_id;
1885              $resourcename=$values['calification_notebook_title'];
1886              $maxqualify=$values['numeric_calification'];
1887              $weigthqualify=$values['weight_calification'];
1888              $resourcedescription='';
1889              $date=time();
1890              //is_resource_in_course_gradebook($course_code, $resource_type, $resource_id);
1891              add_resource_to_course_gradebook($coursecode,$resourcetype,$resourceid,$resourcename,$weigthqualify,$maxqualify,$resourcedescription,$date,0,api_get_session_id());
1892  
1893              }
1894  
1895          api_item_property_update($_course, TOOL_FORUM_THREAD, $last_thread_id,"ForumThreadAdded", api_get_user_id());
1896          // if the forum properties tell that the posts have to be approved we have to put the whole thread invisible
1897          // because otherwise the students will see the thread and not the post in the thread.
1898          // we also have to change $visible because the post itself has to be visible in this case (otherwise the teacher would have
1899          // to make the thread visible AND the post
1900  
1901          if ($visible==0) {
1902              api_item_property_update($_course, TOOL_FORUM_THREAD, $last_thread_id,"invisible", api_get_user_id());
1903              $visible=1;
1904          }
1905          // We now store the content in the table_post table
1906          $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)
1907                  VALUES ('".$clean_post_title."',
1908                  '".Database::escape_string(Security::remove_XSS(stripslashes(api_html_entity_decode($values['post_text'])),COURSEMANAGERLOWSECURITY))."',
1909                  '".Database::escape_string($last_thread_id)."',
1910                  '".Database::escape_string($values['forum_id'])."',
1911                  '".Database::escape_string($_user['user_id'])."',
1912                  '".Database::escape_string(isset($values['poster_name'])?$values['poster_name']:null)."',
1913                  '".Database::escape_string($post_date)."',
1914                  '".Database::escape_string(isset($values['post_notification'])?$values['post_notification']:null)."','0',
1915                  '".Database::escape_string($visible)."')";
1916          Database::query($sql, __FILE__,__LINE__);
1917          $last_post_id=Database::insert_id();
1918  
1919          // 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)
1920          $sql="UPDATE $table_threads SET thread_last_post='".Database::escape_string($last_post_id)."'  WHERE thread_id='".Database::escape_string($last_thread_id)."'";
1921          $result=Database::query($sql, __LINE__, __FILE__);
1922          $message=get_lang('NewThreadStored');
1923          // Storing the attachments if any
1924          if ($has_attachment) {
1925              $courseDir   = $_course['path'].'/upload/forum';
1926              $sys_course_path = api_get_path(SYS_COURSE_PATH);
1927              $updir = $sys_course_path.$courseDir;
1928  
1929              // Try to add an extension to the file if it hasn't one
1930              $new_file_name = add_ext_on_mime(stripslashes($_FILES['user_upload']['name']), $_FILES['user_upload']['type']);
1931  
1932              // user's file name
1933              $file_name =$_FILES['user_upload']['name'];
1934  
1935              if (!filter_extension($new_file_name))  {
1936                  echo get_lang('UplUnableToSaveFileFilteredExtension');
1937              } else {
1938                  if ($result) {
1939                      $comment = Database::escape_string($comment);
1940                      add_forum_attachment_file($comment,$last_post_id);
1941                  }
1942              }
1943          } else {
1944              $message.='<br />';
1945          }
1946  
1947          if ($current_forum['approval_direct_post']=='1' AND !api_is_allowed_to_edit(null,true)) {
1948              $message.=get_lang('MessageHasToBeApproved').'<br />';
1949              $message.=get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&gidReq='.$_SESSION['toolgroup'].'&origin='.$origin.'">'.get_lang('Forum').'</a><br />';
1950          } else {
1951              $message.=get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&gidReq='.$_SESSION['toolgroup'].'&origin='.$origin.'">'.get_lang('Forum').'</a><br />';
1952              $message.=get_lang('ReturnTo').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&origin='.$origin.'&amp;gradebook='.$gradebook.'&amp;thread='.$last_thread_id.'">'.get_lang('Message').'</a>';
1953          }
1954          $reply_info['new_post_id'] = $last_post_id;
1955          $my_post_notification=isset($values['post_notification']) ? $values['post_notification'] : null;
1956          if ($my_post_notification == 1) {
1957              set_notification('thread',$last_thread_id, true);
1958          }
1959  
1960          send_notification_mails($last_thread_id,$reply_info);
1961  
1962          session_unregister('formelements');
1963          session_unregister('origin');
1964          session_unregister('breadcrumbs');
1965          session_unregister('addedresource');
1966          session_unregister('addedresourceid');
1967  
1968          echo '<div class="confirmation-message rounded">'.$message.'</div>';
1969      } else {
1970          echo get_lang('UplNoFileUploaded');
1971      }
1972  }
1973  /**
1974  * This function displays the form that is used to add a post. This can be a new thread or a reply.
1975  * @param $action is the parameter that determines if we are
1976  *                    1. newthread: adding a new thread (both empty) => No I-frame
1977  *                    2. replythread: Replying to a thread ($action = replythread) => I-frame with the complete thread (if enabled)
1978  *                    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)
1979  *                     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)
1980  *
1981  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
1982  * @version february 2006, dokeos 1.8
1983  */
1984  function show_add_post_form($action='', $id='', $form_values='') {
1985      global $forum_setting;
1986      global $current_forum;
1987      global $_user;
1988      global $origin;
1989      global $charset;
1990      $gradebook=Security::remove_XSS($_GET['gradebook']);
1991      // setting the class and text of the form title and submit button
1992      if ($_GET['action']=='quote'){
1993          $class='save';
1994          $text=get_lang('QuoteMessage');
1995      }elseif ($_GET['action'] == 'replythread'){
1996          $class='save';
1997          $text=get_lang('ReplyToThread');
1998      }elseif ($_GET['action']=='replymessage'){
1999          $class='save';
2000          $text=get_lang('ReplyToMessage');
2001      }else {
2002          $class='add';
2003          $text=get_lang('CreateThread');
2004      }
2005  
2006      // initiate the object
2007      $my_thread  = isset($_GET['thread']) ? $_GET['thread']:'';
2008      $my_forum   = isset($_GET['forum'])  ? $_GET['forum']:'';
2009      $my_action  = isset($_GET['action']) ? $_GET['action']:'';
2010      $my_post    = isset($_GET['post'])   ? $_GET['post']:'';
2011      $my_gradebook    = isset($_GET['gradebook']) ? Security::remove_XSS($_GET['gradebook']):'';
2012      $form = new FormValidator('thread', 'post', api_get_self().'?forum='.Security::remove_XSS($my_forum).'&gradebook='.$gradebook.'&thread='.Security::remove_XSS($my_thread).'&post='.Security::remove_XSS($my_post).'&action='.Security::remove_XSS($my_action).'&origin='.$origin);
2013      $renderer = & $form->defaultRenderer();    
2014      $form->setConstants(array('forum' => '5'));
2015  
2016      $form->addElement('header', '', $text);
2017  
2018      // settting the form elements
2019      $form->addElement('hidden', 'forum_id', strval(intval($my_forum)));
2020      $form->addElement('hidden', 'thread_id', strval(intval($my_thread)));
2021      $form->addElement('hidden', 'gradebook', $my_gradebook);
2022  
2023      // if anonymous posts are allowed we also display a form to allow the user to put his name or username in
2024      if ($current_forum['allow_anonymous']==1 AND !isset($_user['user_id'])) {
2025          $form->addElement('text', 'poster_name', get_lang('Name'));
2026          $form->applyFilter('poster_name', 'html_filter');
2027      }
2028      $renderer->setElementTemplate('<div class="row"><div style="width:100%;float:left;">'.get_lang('Title').': {element}</div></div>', 'post_title');
2029      $form->addElement('text', 'post_title', get_lang('Title'),'class="input_titles"');
2030      //$form->applyFilter('post_title', 'html_filter');
2031      $renderer->setElementTemplate('<div class="row"><div style="width:100%;float:right;">{element}</div></div>', 'post_text');
2032      $form->addElement('html_editor', 'post_text', get_lang('Text'), null,
2033          api_is_allowed_to_edit(null,true)
2034              ? array('ToolbarSet' => 'Forum', 'Width' => '100%', 'Height' => '300')
2035              : array('ToolbarSet' => 'ForumStudent', 'Width' => '100%', 'Height' => '300', 'UserStatus' => 'student')
2036      );
2037      //$form->applyFilter('post_text', 'html_filter');
2038  
2039      $form->addElement('html', '<div class="row"><div class="label">');
2040      $form->addElement('html','<a href="javascript://" onclick="return advanced_parameters()"><span id="img_plus_and_minus">&nbsp;'.Display::return_icon('div_show.gif',get_lang('Show'),array('style'=>'vertical-align:middle')).' '.get_lang('AdvancedParameters').'</span></a>','');
2041      $form->addElement('html', '</div><div class="formw"></div></div>');
2042      $form->addElement('html','<div id="id_qualify" style="display:none">');
2043  
2044      if( (api_is_course_admin() || api_is_course_coach() || api_is_course_tutor()) && !($my_thread) ){
2045          // thread qualify
2046  
2047          $form->addElement('static','Group', '<br /><strong>'.get_lang('AlterQualifyThread').'</strong>');
2048          $form->addElement('text', 'numeric_calification', get_lang('QualifyNumeric'),'Style="width:40px"');
2049          $form->applyFilter('numeric_calification', 'html_filter');
2050          $form->addElement('checkbox', 'thread_qualify_gradebook', '', get_lang('QualifyThreadGradebook'),'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"');
2051  
2052          $form -> addElement('html','<div id="options_field" style="display:none">');
2053          $form->addElement('text', 'calification_notebook_title', get_lang('TitleColumnGradebook'));
2054          $form->applyFilter('calification_notebook_title', 'html_filter');
2055          $form->addElement('text', 'weight_calification', get_lang('QualifyWeight'),'value="0.00" Style="width:40px" onfocus="this.select();"');
2056          $form->applyFilter('weight_calification', 'html_filter');
2057          $form->addElement('html','</div>');
2058      }
2059  
2060      if ($forum_setting['allow_post_notificiation'] AND isset($_user['user_id'])) {
2061          $form->addElement('checkbox', 'post_notification', '', get_lang('NotifyByEmail').' ('.$_user['mail'].')');
2062      }
2063  
2064      if ($forum_setting['allow_sticky'] AND api_is_allowed_to_edit(null,true) AND $action=='newthread') {
2065          $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
2066      }
2067  
2068      if ($current_forum['allow_attachments']=='1' OR api_is_allowed_to_edit(null,true)) {
2069          //$form->add_resource_button();
2070          $values = $form->exportValues();
2071      }
2072  
2073      // user upload
2074      $form->addElement('html','<br /><b><div class="row"><div class="label">'.get_lang('AddAnAttachment').'</div></div></b><br /><br />');
2075      $form->addElement('file','user_upload',get_lang('FileName'),'');
2076      $form->addElement('textarea','file_comment',get_lang('FileComment'),array ('rows' => 4, 'cols' => 34));
2077      $form->applyFilter('file_comment', 'html_filter');
2078      $form->addElement('html','</div>');
2079      $userid  =api_get_user_id();
2080      $info    =api_get_user_info($userid);
2081      $courseid=api_get_course_id();
2082  
2083  
2084      $form->addElement('style_submit_button', 'SubmitPost', $text, 'class="'.$class.'"');
2085      $form->add_real_progress_bar('DocumentUpload','user_upload');
2086  
2087      if ( !empty($form_values) ) {
2088          $defaults['post_title']=prepare4display(Security::remove_XSS($form_values['post_title']));
2089          $defaults['post_text']=prepare4display(Security::remove_XSS($form_values['post_text']));
2090          $defaults['post_notification']=Security::remove_XSS($form_values['post_notification']);
2091          $defaults['thread_sticky']=Security::remove_XSS($form_values['thread_sticky']);
2092      }
2093  
2094      // if we are quoting a message we have to retrieve the information of the post we are quoting so that
2095      // we can add this as default to the textarea
2096      if (($action=='quote' || $action=='replymessage') && isset($my_post)) {
2097          // 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 !!!)
2098          $form->addElement('hidden', 'post_parent_id', strval(intval($my_post))); // note this has to be cleaned first
2099  
2100          // if we are replying or are quoting then we display a default title.
2101           $values=get_post_information($my_post); // note: this has to be cleaned first
2102          $defaults['post_title']=get_lang('ReplyShort').api_html_entity_decode($values['post_title'],ENT_QUOTES,$charset);
2103          // When we are quoting a message then we have to put that message into the wysiwyg editor.
2104          // note: the style has to be hardcoded here because using class="quote" didn't work
2105          if($action=='quote') {
2106              $defaults['post_text']='<div>&nbsp;</div><div style="margin: 5px;"><div style="font-size: 90%;    font-style: italic;">'.get_lang('Quoting').' '.api_get_person_name($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>&nbsp;</div><div>&nbsp;</div>';
2107          }
2108      }
2109      $form->setDefaults(isset($defaults)?$defaults:null);
2110  
2111      // the course admin can make a thread sticky (=appears with special icon and always on top)
2112      $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
2113      if ($current_forum['allow_anonymous']==1 AND !isset($_user['user_id'])) {
2114          $form->addRule('poster_name', get_lang('ThisFieldIsRequired'), 'required');
2115      }
2116  
2117      // The validation or display
2118      if( $form->validate() ) {
2119          $check = Security::check_token('post');
2120          if ($check) {
2121                 $values = $form->exportValues();
2122                 if($values['thread_qualify_gradebook']=='1' && empty($values['weight_calification'])){
2123                  Display::display_error_message(get_lang('YouMustAssignWeightOfQualification').'&nbsp;<a href="javascript:window.back()">'.get_lang('Back').'</a>',false);
2124                     return false;
2125                 }
2126                 Security::clear_token();
2127                 return $values;
2128          }
2129  
2130      } else {
2131          $token = Security::get_token();
2132          $form->addElement('hidden','sec_token');
2133          $form->setConstants(array('sec_token' => $token));
2134          $form->display();
2135          echo '<br />';
2136          if ($forum_setting['show_thread_iframe_on_reply'] and $action<>'newthread')
2137          {
2138              echo '<div class="row">
2139                      <div class="label">'.get_lang('Thread').'
2140                      </div>
2141                      <div class="formw">';
2142              echo "<iframe style=\"border: 1px solid black\" src=\"iframe_thread.php?forum=".Security::remove_XSS($my_forum)."&amp;thread=".Security::remove_XSS($my_thread)."#".Security::remove_XSS($my_post)."\" width=\"100%\"></iframe>";
2143              echo '    </div>
2144                  </div>';
2145  
2146  
2147          }
2148      }
2149  }
2150  /**
2151   * @param integer contains the information of user id
2152   * @param integer contains the information of thread id
2153   * @param integer contains the information of thread qualify
2154   * @param integer contains the information of user id of qualifier
2155   * @param integer contains the information of time
2156   * @param integer contains the information of session id
2157   * @return Array() optional
2158   * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
2159   * @version October 2008, dokeos  1.8.6
2160   **/
2161  function store_theme_qualify($user_id,$thread_id,$thread_qualify=0,$qualify_user_id=0,$qualify_time,$session_id=null) {
2162      $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY,'');
2163       $table_threads           =Database::get_course_table(TABLE_FORUM_THREAD,'');
2164          if ($user_id==strval(intval($user_id)) && $thread_id==strval(intval($thread_id)) && $thread_qualify==strval(floatval($thread_qualify))) {
2165  
2166          //testing
2167  
2168          $sql_string="SELECT thread_qualify_max FROM ". $table_threads ." WHERE thread_id=".$thread_id.";";
2169          $res_string=Database::query($sql_string,__FILE__,__LINE__);
2170          $row_string=Database::fetch_array($res_string);
2171          if ($thread_qualify<=$row_string[0]) {
2172  
2173              $sql1="SELECT COUNT(*) FROM ".$table_threads_qualify." WHERE user_id=".$user_id." and thread_id=".$thread_id.";";
2174              $res1=Database::query($sql1);
2175              $row=Database::fetch_array($res1);
2176  
2177              if ($row[0]==0) {
2178                  $sql="INSERT INTO $table_threads_qualify (user_id," .
2179                      "thread_id,qualify,qualify_user_id,qualify_time,session_id)" .
2180                      "VALUES('".$user_id."','".$thread_id."',".(float)$thread_qualify."," .
2181                      "'".$qualify_user_id."','".$qualify_time."','".$session_id."')";
2182                  $res=Database::query($sql,__FILE__,__LINE__);
2183  
2184                  return $res;
2185              } else {
2186  
2187                  $sql1="SELECT qualify FROM ".$table_threads_qualify." WHERE user_id=".$user_id." and thread_id=".$thread_id.";";
2188                  $rs=Database::query($sql1,__FILE__,__LINE__);
2189                  $row=Database::fetch_array($rs);
2190                  $row[1]="update";
2191                  return $row;
2192  
2193              }
2194  
2195          }else{
2196              return null;
2197          }
2198      }
2199  }
2200  /**
2201  * This function show qualify.
2202  * @param string contains the information of option to run
2203  * @param string contains the information the current course id
2204  * @param integer contains the information the current forum id
2205  * @param integer contains the information the current user id
2206  * @param integer contains the information the current thread id
2207  * @return integer qualify
2208  * @example $option=1 obtained the qualification of the current thread
2209  * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
2210  * @version October 2008, dokeos  1.8.6
2211  */
2212   function show_qualify($option,$couser_id,$forum_id,$user_id,$thread_id){
2213  
2214       $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY,'');
2215       $table_threads           =Database::get_course_table(TABLE_FORUM_THREAD,'');
2216      if ($user_id==strval(intval($user_id)) && $thread_id==strval(intval($thread_id)) && $option==1) {
2217  
2218           $sql="SELECT qualify FROM ".$table_threads_qualify." WHERE user_id=".$user_id." and thread_id=".$thread_id.";";
2219          $rs=Database::query($sql,__FILE__,__LINE__);
2220          $row=Database::fetch_array($rs);
2221          return $row[0];
2222       }
2223  
2224      if ($user_id==strval(intval($user_id)) && $option==2) {
2225  
2226           $sql="SELECT thread_qualify_max FROM ".$table_threads." WHERE thread_id=".$thread_id.";";
2227          $rs=Database::query($sql,__FILE__,__LINE__);
2228          $row=Database::fetch_array($rs);
2229          return $row[0];
2230       }
2231  
2232   }
2233   /**
2234  *
2235  *  This function get qualify historical.
2236  * @param integer contains the information the current user id
2237  * @param integer contains the information the current thread id
2238  * @param boolean contains the information of option to run
2239  * @return array()
2240  * @author Christian Fasanando <christian.fasanando@dokeos.com>,
2241  * @author Isaac Flores <isaac.flores@dokeos.com>,
2242  * @version October 2008, dokeos  1.8.6
2243  */
2244   function get_historical_qualify($user_id,$thread_id,$opt) {
2245      $my_qualify_log=array();
2246       $table_threads_qualify_log = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG,'');
2247          if ($opt=='false') {
2248              $sql="SELECT * FROM ".$table_threads_qualify_log." WHERE thread_id='".Database::escape_string($thread_id)."' and user_id='".Database::escape_string($user_id)."' ORDER BY qualify_time";
2249          } else {
2250              $sql="SELECT * FROM ".$table_threads_qualify_log." WHERE thread_id='".Database::escape_string($thread_id)."' and user_id='".Database::escape_string($user_id)."' ORDER BY qualify_time DESC";
2251          }
2252          $rs=Database::query($sql,__FILE__,__LINE__);
2253          while ($row=Database::fetch_array($rs,'ASSOC')) {
2254              $my_qualify_log[]=$row;
2255          }
2256          return $my_qualify_log;
2257   }
2258  
2259  /**
2260  *
2261  *  This function store qualify historical.
2262  * @param boolean contains the information of option to run
2263  * @param string contains the information the current course id
2264  * @param integer contains the information the current forum id
2265  * @param integer contains the information the current user id
2266  * @param integer contains the information the current thread id
2267  * @param integer contains the information the current qualify
2268  * @return void
2269  * @example $option=1 obtained the qualification of the current thread
2270  * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
2271  * @version October 2008, dokeos  1.8.6
2272  */
2273  function store_qualify_historical($option,$couser_id,$forum_id,$user_id,$thread_id,$current_qualify,$qualify_user_id) {
2274  
2275      $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY,'');
2276      $table_threads           =Database::get_course_table(TABLE_FORUM_THREAD,'');
2277      $table_threads_qualify_log=Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY_LOG,'');
2278      $current_date=date('Y-m-d H:i:s');
2279  
2280  
2281      if ($user_id==strval(intval($user_id)) && $thread_id==strval(intval($thread_id)) && $option==1) {
2282           //extract information of thread_qualify
2283  
2284           $sql="SELECT qualify,qualify_time FROM ".$table_threads_qualify." WHERE user_id=".$user_id." and thread_id=".$thread_id.";";
2285          $rs=Database::query($sql,__FILE__,__LINE__);
2286          $row=Database::fetch_array($rs);
2287  
2288          //insert thread_historical
2289          $sql1="INSERT INTO $table_threads_qualify_log (user_id," .
2290                  "thread_id,qualify,qualify_user_id,qualify_time,session_id)" .
2291                  "VALUES('".$user_id."','".$thread_id."',".(float)$row[0]."," .
2292                  "'".$qualify_user_id."','".$row[1]."','')";
2293          Database::query($sql1,__FILE__,__LINE__);
2294  
2295          //update
2296           $sql2="UPDATE ".$table_threads_qualify." SET qualify=".$current_qualify.",qualify_time='".$current_date."' WHERE user_id=".$user_id." and thread_id=".$thread_id.";";
2297          Database::query($sql2,__FILE__,__LINE__);
2298      }
2299  }
2300  /**
2301  *
2302  *  This function show current thread qualify .
2303  * @param integer contains the information the current thread id
2304  * @param integer contains the information the current session id
2305  * @return integer
2306  * @author Isaac Flores <isaac.flores@dokeos.com>, U.N.A.S University
2307  * @version December 2008, dokeos  1.8.6
2308  */
2309  function current_qualify_of_thread($thread_id,$session_id) {
2310  
2311      $table_threads_qualify = Database::get_course_table(TABLE_FORUM_THREAD_QUALIFY,'');
2312      $res=Database::query('SELECT qualify FROM '.$table_threads_qualify.' WHERE thread_id='.$thread_id.' AND session_id='.$session_id);
2313      $row=Database::fetch_array($res,'ASSOC');
2314      return $row['qualify'];
2315  }
2316  /**
2317  * This function stores a reply in the forum_post table.
2318  * It also updates the forum_threads table (thread_replies +1 , thread_last_post, thread_date)
2319  *
2320  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2321  * @version february 2006, dokeos 1.8
2322  */
2323  function store_reply($values) {
2324      global $table_threads;
2325      global $table_posts;
2326      global $forum_table_attachment;
2327      global $_user;
2328      global $_course;
2329      global $current_forum;
2330      global $origin;
2331      $gradebook=Security::remove_XSS($_GET['gradebook']);
2332  
2333      $post_date=date('Y-m-d H:i:s');
2334      if ($current_forum['approval_direct_post']=='1' AND !api_is_allowed_to_edit(null,true)) {
2335          $visible=0; // the post is not approved yet.
2336      } else {
2337          $visible=1;
2338      }
2339  
2340      $upload_ok=1;
2341      $has_attachment=false;
2342      if (!empty($_FILES['user_upload']['name'])) {
2343          $upload_ok = process_uploaded_file($_FILES['user_upload']);
2344          $has_attachment=true;
2345      }
2346  
2347      if ($upload_ok) {
2348          // anonymous or not: if anonymous then we store the poster name that the user has entered
2349          if (api_is_anonymous() OR $_user['user_id'] == 0 OR empty($_user['user_id'])){
2350              $poster_name = $values['poster_name'];
2351          }
2352  
2353          // We first store an entry in the forum_post table
2354          $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)
2355                  VALUES ('".Database::escape_string(Security::remove_XSS($values['post_title']))."',
2356                          '".Database::escape_string(isset($values['post_text']) ? Security::remove_XSS(stripslashes(api_html_entity_decode($values['post_text'])),COURSEMANAGERLOWSECURITY) : null)."',
2357                          '".Database::escape_string($values['thread_id'])."',
2358                          '".Database::escape_string($values['forum_id'])."',
2359                          '".Database::escape_string($_user['user_id'])."',
2360                          '".Database::escape_string($poster_name)."',
2361                          '".Database::escape_string($post_date)."',
2362                          '".Database::escape_string(isset($values['post_notification'])?$values['post_notification']:null)."',
2363                          '".Database::escape_string(isset($values['post_parent_id'])?$values['post_parent_id']:null)."',
2364                          '".Database::escape_string($visible)."')";
2365          $result=Database::query($sql, __LINE__, __FILE__);
2366          $new_post_id=Database::insert_id();
2367          $values['new_post_id']=$new_post_id;
2368  
2369          $message=get_lang('ReplyAdded');
2370  
2371          if ($has_attachment) {
2372              $courseDir   = $_course['path'].'/upload/forum';
2373              $sys_course_path = api_get_path(SYS_COURSE_PATH);
2374              $updir = $sys_course_path.$courseDir;
2375  
2376              // Try to add an extension to the file if it hasn't one
2377              $new_file_name = add_ext_on_mime(stripslashes($_FILES['user_upload']['name']), $_FILES['user_upload']['type']);
2378  
2379              // user's file name
2380              $file_name =$_FILES['user_upload']['name'];
2381  
2382              if (!filter_extension($new_file_name)) {
2383                  Display :: display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
2384              } else {
2385                  $new_file_name = uniqid('');
2386                  $new_path=$updir.'/'.$new_file_name;
2387                  $result= @move_uploaded_file($_FILES['user_upload']['tmp_name'], $new_path);
2388                  $comment=$values['file_comment'];
2389  
2390                  // Storing the attachments if any
2391                  if ($result) {
2392                      $sql='INSERT INTO '.$forum_table_attachment.'(filename,comment, path, post_id,size) '.
2393                           "VALUES ( '".Database::escape_string($file_name)."', '".Database::escape_string($comment)."', '".Database::escape_string($new_file_name)."' , '".$new_post_id."', '".$_FILES['user_upload']['size']."' )";
2394                      $result=Database::query($sql, __LINE__, __FILE__);
2395                      $message.=' / '.get_lang('FileUploadSucces');
2396                      $last_id=Database::insert_id();
2397  
2398                      api_item_property_update($_course, TOOL_FORUM_ATTACH, $last_id ,'ForumAttachmentAdded', api_get_user_id());
2399                  }
2400              }
2401          }
2402  
2403          // update the thread
2404          update_thread($values['thread_id'], $new_post_id,$post_date);
2405  
2406          // update the forum
2407          api_item_property_update($_course, TOOL_FORUM, $values['forum_id'],"NewMessageInForum", api_get_user_id());
2408  
2409  
2410  
2411          if ($current_forum['approval_direct_post']=='1' AND !api_is_allowed_to_edit(null,true)) {
2412              $message.='<br />'.get_lang('MessageHasToBeApproved').'<br />';
2413          }
2414  
2415          $message.='<br />'.get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&origin='.$origin.'">'.get_lang('Forum').'</a><br />';
2416          $message.=get_lang('ReturnTo').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.$values['forum_id'].'&amp;thread='.$values['thread_id'].'&origin='.$origin.'&amp;gradebook='.$gradebook.'">'.get_lang('Message').'</a>';
2417  
2418          // setting the notification correctly
2419          $my_post_notification=isset($values['post_notification']) ? $values['post_notification'] :null;
2420          if ($my_post_notification == 1) {
2421              set_notification('thread',$values['thread_id'], true);
2422          }
2423  
2424          send_notification_mails($values['thread_id'], $values);
2425  
2426          session_unregister('formelements');
2427          session_unregister('origin');
2428          session_unregister('breadcrumbs');
2429          session_unregister('addedresource');
2430          session_unregister('addedresourceid');
2431  
2432          echo '<div class="confirmation-message rounded">'.$message.'</div>';
2433  
2434      } else {
2435          echo get_lang('UplNoFileUploaded')." ". get_lang('UplSelectFileFirst');
2436      }
2437  
2438  }
2439  
2440  
2441  /**
2442  * This function displays the form that is used to edit a post. This can be a new thread or a reply.
2443  * @param array contains all the information about the current post
2444  * @param array contains all the information about the current thread
2445  * @param array contains all info about the current forum (to check if attachments are allowed)
2446  * @param array contains the default values to fill the form
2447  * @return void
2448  *
2449  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2450  * @version february 2006, dokeos 1.8
2451  */
2452  function show_edit_post_form($current_post, $current_thread, $current_forum, $form_values='',$id_attach=0) {
2453      global $forum_setting;
2454      global $_user;
2455      global $origin;
2456      $gradebook=Security::remove_XSS($_GET['gradebook']);
2457  
2458      // initiate the object
2459      $form = new FormValidator('edit_post', 'post', api_get_self().'?forum='.Security::remove_XSS($_GET['forum']).'&gradebook='.$gradebook.'&origin='.$origin.'&thread='.Security::remove_XSS($_GET['thread']).'&post='.Security::remove_XSS($_GET['post']));
2460      $renderer = & $form->defaultRenderer();    
2461      $form->addElement('header', '', get_lang('EditPost'));
2462      // settting the form elements
2463      $form->addElement('hidden', 'post_id', $current_post['post_id']);
2464      $form->addElement('hidden', 'thread_id', $current_thread['thread_id']);
2465      $form->addElement('hidden', 'id_attach', $id_attach);
2466      if ($current_post['post_parent_id']==0) {
2467          $form->addElement('hidden', 'is_first_post_of_thread', '1');
2468      }
2469      $renderer->setElementTemplate('<div class="row"><div style="width:100%;float:left;">'.get_lang('Title').': {element}</div></div>', 'post_title');
2470      $form->addElement('text', 'post_title', get_lang('Title'),'class="input_titles"');
2471      $form->applyFilter('post_title', 'html_filter');
2472      $renderer->setElementTemplate('<div class="row"><div style="width:100%;float:right;">{element}</div></div>', 'post_text');
2473      $form->addElement('html_editor', 'post_text', get_lang('Text'), null,
2474          api_is_allowed_to_edit(null,true)
2475              ? array('ToolbarSet' => 'Forum', 'Width' => '100%', 'Height' => '400')
2476              : array('ToolbarSet' => 'ForumStudent', 'Width' => '100%', 'Height' => '400', 'UserStatus' => 'student')
2477      );
2478      //$form->applyFilter('post_text', 'html_filter');
2479  
2480      $form->addElement('html', '<div class="row"><div class="label">');
2481      $form->addElement('HTML','<a href="javascript://" onclick="return advanced_parameters()"><span id="img_plus_and_minus">'.Display::return_icon('div_show.gif',get_lang('Show'),array('style'=>'vertical-align:middle')).''.get_lang('AdvancedParameters').'</span></a>','');
2482      $form->addElement('html','</div><div class="formw"></div></div>');
2483      $form->addElement('html','<div id="id_qualify" style="display:none">');
2484  
2485      if (!isset($_GET['edit'])) {
2486          $form->addElement('static','Group','<strong>'.get_lang('AlterQualifyThread').'</strong>');
2487          $form->addElement('text', 'numeric_calification', get_lang('QualifyNumeric'),'value="'.$current_thread['thread_qualify_max'].'" Style="width:40px"');
2488          $form->applyFilter('numeric_calification', 'html_filter');
2489          $form->addElement('checkbox', 'thread_qualify_gradebook', '', get_lang('QualifyThreadGradebook'),'onclick="javascript:if(this.checked==true){document.getElementById(\'options_field\').style.display = \'block\';}else{document.getElementById(\'options_field\').style.display = \'none\';}"');
2490          $defaults['thread_qualify_gradebook']=is_resource_in_course_gradebook(api_get_course_id(),5,$_GET['thread'],api_get_session_id());
2491  
2492          if (!empty($defaults['thread_qualify_gradebook'])) {
2493          $form -> addElement('html','<div id="options_field" style="display:block">');
2494          } else {
2495              $form -> addElement('html','<div id="options_field" style="display:none">');
2496          }
2497          $form->addElement('text', 'calification_notebook_title', get_lang('TitleColumnGradebook'),'value="'.$current_thread['thread_title_qualify'].'"');
2498          $form->applyFilter('calification_notebook_title', 'html_filter');
2499          $form->addElement('text', 'weight_calification', get_lang('QualifyWeight'),'value="'.$current_thread['thread_weight'].'" Style="width:40px"');
2500          $form->applyFilter('weight_calification', 'html_filter');
2501          $form->addElement('html','</div>');
2502          //add gradebook
2503      }
2504  
2505      if ($forum_setting['allow_post_notificiation']) {
2506          $form->addElement('checkbox', 'post_notification', '', get_lang('NotifyByEmail').' ('.$current_post['email'].')');
2507      }
2508      if ($forum_setting['allow_sticky'] and api_is_allowed_to_edit(null,true) and $current_post['post_parent_id']==0) { // the sticky checkbox only appears when it is the first post of a thread
2509          $form->addElement('checkbox', 'thread_sticky', '', get_lang('StickyPost'));
2510          if ( $current_thread['thread_sticky']==1 ) {
2511              $defaults['thread_sticky']=true;
2512          }
2513      }
2514  
2515      $attachment_list=get_attachment($current_post['post_id']);
2516      $message=get_lang('AddAnAttachment');
2517      if (!empty($attachment_list)) {
2518          $message=get_lang('EditAnAttachment');
2519          $form->addElement('static','Group','','<br />'.Display::return_icon('attachment.gif',get_lang('Attachment')).'&nbsp;'.$attachment_list['filename'].(!empty($attachment_list['comment'])?'('.$attachment_list['comment'].')':''));
2520          $form->addElement('checkbox', 'remove_attach', null, get_lang('DeleteAttachmentFile'));
2521      }
2522      // user upload
2523      $form->addElement('html','<br /><b><div class="row"><div class="label">'.$message.'</div></div></b><br /><br />');
2524      $form->addElement('file','user_upload',get_lang('FileName'),'');
2525      $form->addElement('textarea','file_comment',get_lang('FileComment'),array ('rows' => 4, 'cols' => 34));
2526      $form->applyFilter('file_comment', 'html_filter');
2527      $form->addElement('html','</div><br /><br />');
2528      if ($current_forum['allow_attachments']=='1' OR api_is_allowed_to_edit(null,true)) {
2529          if (empty($form_values) AND !isset($_POST['SubmitPost'])) {
2530              //edit_added_resources('forum_post',$current_post['post_id']);
2531          }
2532          //$form->add_resource_button();
2533          $values = $form->exportValues();
2534      }
2535  
2536      $form->addElement('style_submit_button', 'SubmitPost', get_lang('ModifyThread'), 'class="save"');
2537      global $charset;
2538      // setting the default values for the form elements
2539      $defaults['post_title']=prepare4display(api_html_entity_decode($current_post['post_title'],ENT_QUOTES,$charset));
2540      $defaults['post_text']=prepare4display($current_post['post_text']);
2541      if ( $current_post['post_notification']==1 ) {
2542          $defaults['post_notification']=true;
2543      }
2544  
2545      if (!empty($form_values)) {
2546          //$defaults['post_title']=Security::remove_XSS($form_values['post_title']);
2547          //$defaults['post_text']=Security::remove_XSS($form_values['post_text']);
2548          $defaults['post_notification']=Security::remove_XSS($form_values['post_notification']);
2549          $defaults['thread_sticky']=Security::remove_XSS($form_values['thread_sticky']);
2550      }
2551  
2552      $form->setDefaults($defaults);
2553  
2554      // the course admin can make a thread sticky (=appears with special icon and always on top)
2555  
2556      $form->addRule('post_title', get_lang('ThisFieldIsRequired'), 'required');
2557  
2558      // The validation or display
2559      if( $form->validate() ) {
2560         $values = $form->exportValues();
2561         if($values['thread_qualify_gradebook']=='1' && empty($values['weight_calification'])){
2562                  Display::display_error_message(get_lang('YouMustAssignWeightOfQualification').'&nbsp;<a href="javascript:window.back()">'.get_lang('Back').'</a>',false);
2563                     return false;
2564         }
2565         return $values;
2566      } else {
2567          $form->display();
2568      }
2569  }
2570  
2571  /**
2572  * This function stores the edit of a post in the forum_post table.
2573  *
2574  * @param
2575  * @return
2576  *
2577  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2578  * @version february 2006, dokeos 1.8
2579  */
2580  function store_edit_post($values) {
2581      global $table_threads;
2582      global $table_posts;
2583      global $origin;
2584      $gradebook=Security::remove_XSS($_GET['gradebook']);
2585      // first we check if the change affects the thread and if so we commit the changes (sticky and post_title=thread_title are relevant)
2586      //if (array_key_exists('is_first_post_of_thread',$values)  AND $values['is_first_post_of_thread']=='1') {
2587          $sql="UPDATE $table_threads SET thread_title='".Database::escape_string($values['post_title'])."',
2588                      thread_sticky='".Database::escape_string(isset($values['thread_sticky']) ? $values['thread_sticky'] : null)."'," .
2589                      "thread_title_qualify='".Database::escape_string($values['calification_notebook_title'])."'," .
2590                      "thread_qualify_max='".Database::escape_string($values['numeric_calification'])."',".
2591                      "thread_weight='".Database::escape_string($values['weight_calification'])."'".
2592                      " WHERE thread_id='".Database::escape_string($values['thread_id'])."'";
2593  
2594          Database::query($sql,__FILE__, __LINE__);
2595      //}
2596      // update the post_title and the post_text
2597      $sql="UPDATE $table_posts SET post_title='".Database::escape_string(Security::remove_XSS($values['post_title']))."',
2598                  post_text='".Database::escape_string(Security::remove_XSS(stripslashes(api_html_entity_decode($values['post_text'])),COURSEMANAGERLOWSECURITY))."',
2599                  post_notification='".Database::escape_string(isset($values['post_notification'])?$values['post_notification']:null)."'
2600                  WHERE post_id='".Database::escape_string($values['post_id'])."'";
2601                  //error_log($sql);
2602      Database::query($sql,__FILE__, __LINE__);
2603  
2604      if (!empty($values['remove_attach'])) {
2605          delete_attachment($values['post_id']);
2606      }
2607  
2608      if (empty($values['id_attach'])) {
2609          add_forum_attachment_file($values['file_comment'],$values['post_id']);
2610      } else {
2611          edit_forum_attachment_file($values['file_comment'],$values['post_id'],$values['id_attach']);
2612      }
2613  
2614      if (api_is_course_admin()==true) {
2615          $ccode = api_get_course_id();
2616          $sid = api_get_session_id();
2617          $link_id = is_resource_in_course_gradebook($ccode,5,$values['thread_id'],$sid);
2618          $thread_qualify_gradebook=isset($values['thread_qualify_gradebook']) ? $values['thread_qualify_gradebook'] : null;
2619          if ($thread_qualify_gradebook!=1) {
2620              if ($link_id !== false) {
2621                  remove_resource_from_course_gradebook($link_id);
2622              }
2623          } else {
2624              if ($link_id === false && !$_GET['thread']) {
2625                  //$date_in_gradebook=date('Y-m-d H:i:s');
2626                  $date_in_gradebook=null;
2627                  $weigthqualify=$values['weight_calification'];
2628                     add_resource_to_course_gradebook($ccode,5,$values['thread_id'],Database::escape_string($values['calification_notebook_title']),$weigthqualify,$values['numeric_calification'],null,$date_in_gradebook,0,$sid);
2629              }
2630          }
2631      }
2632      // Storing the attachments if any
2633      //update_added_resources('forum_post',$values['post_id']);
2634  
2635      $message=get_lang('EditPostStored').'<br />';
2636      $message.=get_lang('ReturnTo').' <a href="viewforum.php?'.api_get_cidreq().'&forum='.Security::remove_XSS($_GET['forum']).'&amp;gidReq='.$_SESSION['toolgroup'].'&amp;origin='.$origin.'">'.get_lang('Forum').'</a><br />';
2637      $message.=get_lang('ReturnTo').' <a href="viewthread.php?'.api_get_cidreq().'&forum='.Security::remove_XSS($_GET['forum']).'&amp;gidReq='.$_SESSION['toolgroup'].'&amp;origin='.$origin.'&amp;gradebook='.$gradebook.'&amp;thread='.$values['thread_id'].'&amp;post='.Security::remove_XSS($_GET['post']).'">'.get_lang('Message').'</a>';
2638  
2639      session_unregister('formelements');
2640      session_unregister('origin');
2641      session_unregister('breadcrumbs');
2642      session_unregister('addedresource');
2643      session_unregister('addedresourceid');
2644  
2645      echo '<div class="confirmation-message rounded">'.$message.'</div>';
2646  }
2647  
2648  
2649  /**
2650  * This function displays the firstname and lastname of the user as a link to the user tool.
2651  *
2652  * @param
2653  * @return
2654  *
2655  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2656  * @version february 2006, dokeos 1.8
2657  */
2658  function display_user_link($user_id, $name, $origin='') {
2659      if ($user_id<>0) {
2660          return '<a href="../user/userInfo.php?uInfo='.$user_id.'" '. (!empty($origin)? 'target="_self"': '') .'>'.$name.'</a>';
2661      } else {
2662          return $name.' ('.get_lang('Anonymous').')';
2663      }
2664  }
2665  
2666  /**
2667  * This function displays the user image from the profile, with a link to the user's details.
2668  * @param     int     User's database ID
2669  * @param     str     User's name
2670  * @return     string     An HTML with the anchor and the image of the user
2671  * @author Julio Montoya <julio.montoya@dokeos.com>
2672  */
2673  
2674  function display_user_image($user_id,$name, $origin='') {
2675      $link='<a href="../user/userInfo.php?uInfo='.$user_id.'" '. (!empty($origin)? 'target="_self"': '') .'>';
2676      $attrb=array();
2677      $str_link = '';
2678      if ($user_id<>0) {
2679          $image_path = UserManager::get_user_picture_path_by_id($user_id,'web',false, true);
2680          $image_repository = $image_path['dir'];
2681          $existing_image = $image_path['file'];
2682          $friends_profile = UserManager::get_picture_user($user_id, $image_path['file'], 0, 'medium_');
2683          if ($origin != 'learnpath') $str_link = $link;
2684          $str_link.='<img src="'.$friends_profile['file'].'" '.$friends_profile['style'].' alt="'.$name.'"  title="'.$name.'" />';
2685          if ($origin != 'learnpath') $str_link.='</a>';
2686          return $str_link;
2687      } else {
2688        if ($origin != 'learnpath') $str_link = $link;
2689        $str_link.='<img src="'.api_get_path(WEB_CODE_PATH)."img/unknown.jpg".'" alt="'.$name.'"  title="'.$name.'"  />';
2690        if ($origin != 'learnpath') $str_link.='</a>';
2691        return $str_link;
2692      }
2693  
2694  }
2695  
2696  
2697  /**
2698  * The thread view counter gets increased every time someone looks at the thread
2699  *
2700  * @param
2701  * @return
2702  *
2703  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2704  * @version february 2006, dokeos 1.8
2705  */
2706  function increase_thread_view($thread_id) {
2707      global $table_threads;
2708  
2709      $sql="UPDATE $table_threads SET thread_views=thread_views+1 WHERE thread_id='".Database::escape_string($thread_id)."'"; // this needs to be cleaned first
2710      $result=Database::query($sql, __LINE__, __FILE__);
2711  }
2712  
2713  /**
2714  * The relies counter gets increased every time somebody replies to the thread
2715  *
2716  * @param
2717  * @return
2718  *
2719  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2720  * @version february 2006, dokeos 1.8
2721  */
2722  function update_thread($thread_id, $last_post_id,$post_date) {
2723      global $table_threads;
2724  
2725      $sql="UPDATE $table_threads SET thread_replies=thread_replies+1,
2726              thread_last_post='".Database::escape_string($last_post_id)."',
2727              thread_date='".Database::escape_string($post_date)."' WHERE thread_id='".Database::escape_string($thread_id)."'"; // this needs to be cleaned first
2728      $result=Database::query($sql, __LINE__, __FILE__);
2729  }
2730  
2731  
2732  
2733  /**
2734  * This function is called when the user is not allowed in this forum/thread/...
2735  *
2736  * @param
2737  * @return
2738  *
2739  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2740  * @version february 2006, dokeos 1.8
2741  */
2742  function forum_not_allowed_here() {
2743      Display :: display_error_message(get_lang('NotAllowedHere'));
2744      Display :: display_footer();
2745      exit;
2746  }
2747  
2748  /**
2749  * This function is used to find all the information about what's new in the forum tool
2750  *
2751  * @param
2752  * @return
2753  *
2754  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2755  * @version february 2006, dokeos 1.8
2756  */
2757  function get_whats_new() {
2758      global $_user;
2759      global $_course;
2760      global $table_posts;
2761  
2762      // note this has later to be replaced by the tool constant. But temporarily bb_forum is used since this is the only thing that is in the tracking currently.
2763      //$tool=TOOL_FORUM;
2764      $tool=TOOL_FORUM; //
2765      // to do: remove this. For testing purposes only
2766      //session_unregister('last_forum_access');
2767      //session_unregister('whatsnew_post_info');
2768  
2769      // to determine if we need to reload the the whatsnew_post_info we compare the last date that something is post with the one
2770      // that is stored in the session. The reason for this is that we want to know if somebody has added something new since the last time the whatsnew_post_info 
2771      // information has been retrieved from the database (and this query is a lot faster than always (unconditionally) getting the whatsnew_post_info information
2772      $sql="SELECT * FROM ".$table_posts." WHERE poster_id <> ".$_user['user_id']." ORDER BY post_id DESC";
2773      $result=api_sql_query($sql,__FILE__,__LINE__);
2774      $row=Database::fetch_array($result);
2775      if ($row['post_date'] > $_SESSION['last_post_date'])
2776      {
2777          $_SESSION['last_post_date'] = $row['post_date'];
2778          session_unregister('whatsnew_post_info');
2779          $whats_new_reloaded = true; 
2780      }
2781  
2782      // checking if we need to retrieve the information of the last time the user visited the forum
2783      if (!$_SESSION['last_forum_access']) {
2784          $tracking_last_tool_access=Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2785          $sql="SELECT * FROM ".$tracking_last_tool_access." WHERE access_user_id='".Database::escape_string($_user['user_id'])."' AND access_cours_code='".Database::escape_string($_course['sysCode'])."' AND access_tool='".Database::escape_string($tool)."'";
2786          $result=Database::query($sql,__FILE__,__LINE__);
2787          $row=Database::fetch_array($result);
2788          $_SESSION['last_forum_access']=$row['access_date'];
2789      }
2790  
2791      // getting all the information that is new for the user
2792      if (!$_SESSION['whatsnew_post_info']) {
2793          if ($_SESSION['last_forum_access']<>'') {
2794              $whatsnew_post_info = array();
2795              $sql="SELECT * FROM ".$table_posts." WHERE post_date>'".Database::escape_string($_SESSION['last_forum_access'])."' AND poster_id <> ".$_user['user_id'].""; // note: check the performance of this query.
2796              $result=Database::query($sql,__FILE__,__LINE__);
2797              while ($row=Database::fetch_array($result)) {
2798                  // if the what's new information has been reloaded (because somebody else has posted a message while we are watching other new messages) 
2799                  // then we only have to add to the what's new info if it has not been seen yet. 
2800                  if ($whats_new_reloaded){
2801                      if ($_SESSION['whatsnew_post_viewed'][$row['forum_id']][$row['thread_id']][$row['post_id']] == false){
2802                          $whatsnew_post_info[$row['forum_id']][$row['thread_id']][$row['post_id']]=$row['post_date'];
2803                      }
2804                  }
2805                  // the what's new information has not been reloaded, so we add everyhting that is new to $whatsnew_post_info 
2806                  else{ 
2807                      $whatsnew_post_info[$row['forum_id']][$row['thread_id']][$row['post_id']]=$row['post_date'];
2808                  }
2809              }
2810              $_SESSION['whatsnew_post_info']=$whatsnew_post_info;
2811          }
2812      }
2813  }
2814  
2815  /**
2816  * With this function we find the number of posts and topics in a given forum.
2817  *
2818  * @param
2819  * @return
2820  *
2821  * @todo consider to call this function only once and let it return an array where the key is the forum id and the value is an array with number_of_topics and number of post
2822  * as key of this array and the value as a value. This could reduce the number of queries needed (especially when there are more forums)
2823  * @todo consider merging both in one query.
2824  *
2825  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2826  * @version february 2006, dokeos 1.8
2827  *
2828  * @deprecated the counting mechanism is now inside the function get_forums
2829  */
2830  function get_post_topics_of_forum($forum_id) {
2831      global $table_posts;
2832      global $table_threads;
2833      global $table_item_property;
2834  
2835      $sql="SELECT count(*) as number_of_posts FROM $table_posts WHERE forum_id='".$forum_id."'";
2836      if (api_is_allowed_to_edit(null,true)) {
2837          $sql="SELECT count(*) as number_of_posts
2838                  FROM $table_posts posts, $table_threads threads, $table_item_property item_property
2839                  WHERE posts.forum_id='".Database::escape_string($forum_id)."'
2840                  AND posts.thread_id=threads.thread_id
2841                  AND item_property.ref=threads.thread_id
2842                  AND item_property.visibility<>2
2843                  AND item_property.tool='".TOOL_FORUM_THREAD."'
2844                  ";
2845      } else {
2846          $sql="SELECT count(*) as number_of_posts
2847                  FROM $table_posts posts, $table_threads threads, $table_item_property item_property
2848                  WHERE posts.forum_id='".Database::escape_string($forum_id)."'
2849                  AND posts.thread_id=threads.thread_id
2850                  AND item_property.ref=threads.thread_id
2851                  AND item_property.visibility=1
2852                  AND posts.visible=1
2853                  AND item_property.tool='".TOOL_FORUM_THREAD."'
2854                  ";
2855      }
2856      $result=Database::query($sql, __FILE__, __LINE__);
2857      $row=Database::fetch_array($result);
2858      $number_of_posts=$row['number_of_posts'];
2859  
2860      // we could loop through the result array and count the number of different group_ids but I have chosen to use a second sql statement
2861      if (api_is_allowed_to_edit(null,true)) {
2862          $sql="SELECT count(*) as number_of_topics
2863                  FROM $table_threads threads, $table_item_property item_property
2864                  WHERE threads.forum_id='".Database::escape_string($forum_id)."'
2865                  AND item_property.ref=threads.thread_id
2866                  AND item_property.visibility<>2
2867                  AND item_property.tool='".TOOL_FORUM_THREAD."'
2868                  ";
2869      } else {
2870          $sql="SELECT count(*) as number_of_topics
2871                  FROM $table_threads threads, $table_item_property item_property
2872                  WHERE threads.forum_id='".Database::escape_string($forum_id)."'
2873                  AND item_property.ref=threads.thread_id
2874                  AND item_property.visibility=1
2875                  AND item_property.tool='".TOOL_FORUM_THREAD."'
2876                  ";
2877      }
2878      $result=Database::query($sql, __FILE__, __LINE__);
2879      $row=Database::fetch_array($result);
2880      $number_of_topics=$row['number_of_topics'];
2881      if ($number_of_topics=='') {
2882          $number_of_topics=0; // due to the nature of the group by this can result in an empty string.
2883      }
2884  
2885      $return=array('number_of_topics'=>$number_of_topics, 'number_of_posts'=>$number_of_posts);
2886      return $return;
2887  }
2888  /**
2889  * This function approves a post = change
2890  *
2891  * @param $post_id the id of the post that will be deleted
2892  * @param $action make the post visible or invisible
2893  * @return
2894  *
2895  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2896  * @version february 2006, dokeos 1.8
2897  */
2898  function approve_post($post_id, $action) {
2899      global $table_posts;
2900  
2901      if ($action=='invisible') {
2902          $visibility_value=0;
2903      }
2904      if ($action=='visible') {
2905          $visibility_value=1;
2906          handle_mail_cue('post',$post_id);
2907      }
2908  
2909      $sql="UPDATE $table_posts SET visible='".Database::escape_string($visibility_value)."' WHERE post_id='".Database::escape_string($post_id)."'";
2910      $return=Database::query($sql, __FILE__, __LINE__);
2911      if ($return) {
2912          return 'PostVisibilityChanged';
2913      }
2914  }
2915  
2916  
2917  /**
2918  * This function retrieves all the unapproved messages for a given forum
2919  * This is needed to display the icon that there are unapproved messages in that thread (only the courseadmin can see this)
2920  *
2921  * @param $forum_id the forum where we want to know the unapproved messages of
2922  * @return
2923  *
2924  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2925  * @version february 2006, dokeos 1.8
2926  */
2927  function get_unaproved_messages($forum_id) {
2928      global $table_posts;
2929  
2930      $return_array=array();
2931      $sql="SELECT DISTINCT thread_id FROM $table_posts WHERE forum_id='".Database::escape_string($forum_id)."' AND visible='0'";
2932      $result=Database::query($sql, __FILE__, __LINE__);
2933      while($row=Database::fetch_array($result)) {
2934          $return_array[]=$row['thread_id'];
2935      }
2936      return $return_array;
2937  }
2938  
2939  
2940  /**
2941  * This function sends the notification mails to everybody who stated that they wanted to be informed when a new post
2942  * was added to a given thread.
2943  *
2944  * @param
2945  * @return
2946  *
2947  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
2948  * @version february 2006, dokeos 1.8
2949  */
2950  function send_notification_mails($thread_id, $reply_info) {
2951      global $table_posts;
2952      global $table_user;
2953      global $table_mailcue;
2954  
2955      // First we need to check if
2956      // 1. the forum category is visible
2957      // 2. the forum is visible
2958      // 3. the thread is visible
2959      // 4. the reply is visible (=when there is
2960      $current_thread=get_thread_information($thread_id);
2961      $current_forum=get_forum_information($current_thread['forum_id']);
2962      $current_forum_category=get_forumcategory_information($current_forum['forum_category']);
2963      if($current_thread['visibility']=='1' AND $current_forum['visibility']=='1' AND $current_forum_category['visibility']=='1' AND $current_forum['approval_direct_post']!='1') {
2964          $send_mails=true;
2965      } else {
2966          $send_mails=false;
2967      }
2968  
2969      // the forum category, the forum, the thread and the reply are visible to the user
2970      if ($send_mails==true) {
2971          send_notifications($current_thread['forum_id'],$thread_id);
2972          /*
2973          $sql="SELECT DISTINCT user.firstname, user.lastname, user.email, user.user_id
2974                  FROM $table_posts post, $table_user user
2975                  WHERE post.thread_id='".Database::escape_string($thread_id)."'
2976                  AND post.post_notification='1'
2977                  AND post.poster_id=user.user_id";
2978          $result=Database::query($sql, __LINE__, __FILE__);
2979          while ($row=Database::fetch_array($result))
2980          {
2981              send_mail($row, $current_thread);
2982          }
2983          */
2984      } else {
2985          /*
2986          $sql="SELECT * FROM $table_posts WHERE thread_id='".Database::escape_string($thread_id)."' AND post_notification='1'";
2987          $result=Database::query($sql, __LINE__, __FILE__);
2988          */
2989          $table_notification = Database::get_course_table(TABLE_FORUM_NOTIFICATION);
2990          $sql = "SELECT * FROM $table_notification WHERE forum_id = '".Database::escape_string($current_forum['forum_id'])."' OR thread_id = '".Database::escape_string($thread_id)."'";
2991          $result=Database::query($sql, __FILE__, __LINE__);
2992          while ($row=Database::fetch_array($result)) {
2993              $sql_mailcue="INSERT INTO $table_mailcue (thread_id, post_id) VALUES ('".Database::escape_string($thread_id)."', '".Database::escape_string($reply_info['new_post_id'])."')";
2994              $result_mailcue=Database::query($sql_mailcue, __LINE__, __FILE__);
2995          }
2996      }
2997  }
2998  
2999  /**
3000  * This function is called whenever something is made visible because there might be new posts and the user might have indicated that (s)he wanted
3001  * to be informed about the new posts by mail.
3002  *
3003  * @param
3004  * @return
3005  *
3006  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3007  * @version february 2006, dokeos 1.8
3008  */
3009  function handle_mail_cue($content, $id) {
3010      global $table_mailcue;
3011      global $table_forums;
3012      global $table_threads;
3013      global $table_posts;
3014      global $table_users;
3015  
3016      // if the post is made visible we only have to send mails to the people who indicated that they wanted to be informed for that thread.
3017      if ($content=='post') {
3018          // getting the information about the post (need the thread_id)
3019          $post_info=get_post_information($id);
3020  
3021          // sending the mail to all the users that wanted to be informed for replies on this thread.
3022          $sql="SELECT users.firstname, users.lastname, users.user_id, users.email FROM $table_mailcue mailcue, $table_posts posts, $table_users users
3023                  WHERE posts.thread_id='".Database::escape_string($post_info['thread_id'])."'
3024                  AND posts.post_notification='1'
3025                  AND mailcue.thread_id='".Database::escape_string($post_info['thread_id'])."'
3026                  AND users.user_id=posts.poster_id
3027                  GROUP BY users.email";
3028          $result=Database::query($sql, __FILE__, __LINE__);
3029          while ($row=Database::fetch_array($result)) {
3030              send_mail($row, get_thread_information($post_info['thread_id']));
3031          }
3032  
3033          // deleting the relevant entries from the mailcue
3034          $sql_delete_mailcue="DELETE FROM $table_mailcue WHERE post_id='".Database::escape_string($id)."' AND thread_id='".Database::escape_string($post_info['thread_id'])."'";
3035          //$result=Database::query($sql_delete_mailcue, __LINE__, __FILE__);
3036      } elseif ($content=='thread') {
3037          // sending the mail to all the users that wanted to be informed for replies on this thread.
3038          $sql="SELECT users.firstname, users.lastname, users.user_id, users.email FROM $table_mailcue mailcue, $table_posts posts, $table_users users
3039                  WHERE posts.thread_id='".Database::escape_string($id)."'
3040                  AND posts.post_notification='1'
3041                  AND mailcue.thread_id='".Database::escape_string($id)."'
3042                  AND users.user_id=posts.poster_id
3043                  GROUP BY users.email";
3044          $result=Database::query($sql,__FILE__, __LINE__);
3045          while ($row=Database::fetch_array($result)) {
3046              send_mail($row, get_thread_information($id));
3047          }
3048  
3049          // deleting the relevant entries from the mailcue
3050          $sql_delete_mailcue="DELETE FROM $table_mailcue WHERE thread_id='".Database::escape_string($id)."'";
3051          $result=Database::query($sql_delete_mailcue, __FILE__, __LINE__);
3052      } elseif ($content=='forum') {
3053          $sql="SELECT * FROM $table_threads WHERE forum_id='".Database::escape_string($id)."'";
3054          $result=Database::query($sql, __FILE__, __LINE__);
3055          while ($row=Database::fetch_array($result)) {
3056              handle_mail_cue('thread',$row['thread_id']);
3057          }
3058      } elseif ($content=='forum_category') {
3059          $sql="SELECT * FROM $table_forums WHERE forum_category ='".Database::escape_string($id)."'";
3060          $result=Database::query($sql, __FILE__, __LINE__);
3061          while ($row=Database::fetch_array($result)) {
3062              handle_mail_cue('forum',$row['forum_id']);
3063          }
3064      } else {
3065          return get_lang('Error');
3066      }
3067  }
3068  /**
3069  * This function sends the mails for the mail notification
3070  *
3071  * @param
3072  * @return
3073  *
3074  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3075  * @version february 2006, dokeos 1.8
3076  */
3077  function send_mail($user_info=array(), $thread_information=array()) {
3078      global $_course;
3079      global $_user;
3080  
3081      $email_subject = get_lang('NewForumPost')." - ".$_course['official_code'];
3082  
3083      if (isset($thread_information) and is_array($thread_information)) {
3084          $thread_link= api_get_path('WEB_CODE_PATH').'forum/viewthread.php?'.api_get_cidreq().'&forum='.$thread_information['forum_id'].'&thread='.$thread_information['thread_id'];
3085      }
3086      $email_body = api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS)."\n\r";
3087      $email_body .= '['.$_course['official_code'].'] - ['.$_course['name']."]<br>\n";
3088      $email_body .= get_lang('NewForumPost')."\n";
3089      $email_body .= get_lang('YouWantedToStayInformed')."<br><br>\n";
3090      $email_body .= get_lang('ThreadCanBeFoundHere')." : <a href=\"".$thread_link."\">".$thread_link."</a>\n";
3091  
3092      //set the charset and use it for the encoding of the email - small fix, not really clean (should check the content encoding origin first)
3093      //here we use the encoding used for the webpage where the text is encoded (ISO-8859-1 in this case)
3094      if(empty($charset)) {
3095          $charset='ISO-8859-1';
3096      }
3097  
3098      if ($user_info['user_id']<>$_user['user_id']) {
3099          $newmail = api_mail_html(api_get_person_name($user_info['firstname'], $user_info['lastname'], null, PERSON_NAME_EMAIL_ADDRESS), $user_info['email'], $email_subject, $email_body, api_get_person_name($_SESSION['_user']['firstName'], $_SESSION['_user']['lastName'], null, PERSON_NAME_EMAIL_ADDRESS), $_SESSION['_user']['mail']);
3100      }
3101  }
3102  
3103  /**
3104  * This function displays the form for moving a thread to a different (already existing) forum
3105  *
3106  * @param
3107  * @return
3108  *
3109  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3110  * @version february 2006, dokeos 1.8
3111  */
3112  function move_thread_form() {
3113      global $origin;
3114      $gradebook=Security::remove_XSS($_GET['gradebook']);
3115      // initiate the object
3116      $form = new FormValidator('movepost', 'post', api_get_self().'?forum='.Security::remove_XSS($_GET['forum']).'&gradebook='.$gradebook.'&thread='.Security::remove_XSS($_GET['thread']).'&action='.Security::remove_XSS($_GET['action']).'&origin='.$origin, null, array('class' => 'outer_form'));
3117      // the header for the form
3118      $form->addElement('header', '', get_lang('MoveThread'));
3119      // invisible form: the thread_id
3120      $form->addElement('hidden', 'thread_id', strval(intval($_GET['thread']))); // note: this has to be cleaned first
3121  
3122      // the fora
3123      $forum_categories=get_forum_categories();
3124      $forums=get_forums();
3125  
3126      $htmlcontent .= '    <div class="row">
3127          <div class="label">
3128              <span class="form_required">*</span>'.get_lang('MoveTo').'
3129          </div>
3130          <div class="formw">';
3131      $htmlcontent .= "<SELECT NAME='forum'>\n";
3132      foreach ($forum_categories as $key=>$category) {
3133          $htmlcontent.="\t<OPTGROUP LABEL=\"".$category['cat_title']."\">\n";
3134          foreach ($forums as $key=>$forum) {
3135              if ($forum['forum_category']==$category['cat_id']) {
3136                  $htmlcontent.="\t\t<OPTION VALUE='".$forum['forum_id']."'>".$forum['forum_title']."</OPTION>\n";
3137              }
3138          }
3139          $htmlcontent.="\t</OPTGROUP>\n";
3140      }
3141      $htmlcontent.="</SELECT>\n";
3142      $htmlcontent .= '    </div>
3143                      </div>';
3144  
3145      $form->addElement('html',$htmlcontent);
3146  
3147      // The OK button
3148      $form->addElement('style_submit_button', 'SubmitForum',get_lang('MoveThread'),'class="save"');
3149  
3150      // The validation or display
3151      if( $form->validate()) {
3152         $values = $form->exportValues();
3153         if (isset($_POST['forum'])) {
3154                 store_move_thread($values);
3155         }
3156  
3157      } else {
3158          $form->display();
3159      }
3160  }
3161  
3162  /**
3163  * This function displays the form for moving a post message to a different (already existing) or a new thread.
3164  *
3165  * @param
3166  * @return
3167  *
3168  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3169  * @version february 2006, dokeos 1.8
3170  */
3171  function move_post_form() {
3172      global $origin;
3173      $gradebook=Security::remove_XSS($_GET['gradebook']);
3174      // initiate the object
3175      $form = new FormValidator('movepost', 'post', api_get_self().'?forum='.Security::remove_XSS($_GET['forum']).'&thread='.Security::remove_XSS($_GET['thread']).'&origin='.$origin.'&gradebook='.$gradebook.'&post='.Security::remove_XSS($_GET['post']).'&action='.Security::remove_XSS($_GET['action']).'&post='.Security::remove_XSS($_GET['post']), null, array('class' => 'outer_form'));
3176      // the header for the form
3177      $form->addElement('header', '', get_lang('MovePost'));
3178  
3179      // invisible form: the post_id
3180      $form->addElement('hidden', 'post_id', strval(intval($_GET['post']))); // note: this has to be cleaned first
3181  
3182      // dropdown list: Threads of this forum
3183      $threads=get_threads(strval(intval($_GET['forum']))); // note: this has to be cleaned
3184      //my_print_r($threads);
3185      $threads_list[0]=get_lang('ANewThread');
3186      foreach ($threads as $key=>$value) {
3187          $threads_list[$value['thread_id']]=$value['thread_title'];
3188      }
3189      $form->addElement('select', 'thread', get_lang('MoveToThread'), $threads_list);
3190      $form->applyFilter('thread', 'html_filter');
3191  
3192      // The OK button
3193      $form->addElement('style_submit_button', 'submit',get_lang('MovePost'),'class="save"');
3194  
3195      // setting the rules
3196      $form->addRule('thread', get_lang('ThisFieldIsRequired'), 'required');
3197  
3198  
3199      // The validation or display
3200      if( $form->validate() ) {
3201         $values = $form->exportValues();
3202         store_move_post($values);
3203      } else {
3204          $form->display();
3205      }
3206  }
3207  
3208  /**
3209  *
3210  * @param
3211  * @return
3212  *
3213  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3214  * @version february 2006, dokeos 1.8
3215  */
3216  function store_move_post($values) {
3217      global $table_posts;
3218      global $table_threads;
3219      global $table_forums;
3220      global $_course;
3221  
3222      if ($values['thread']=='0') {
3223          $current_post=get_post_information($values['post_id']);
3224  
3225          // storing a new thread
3226          $sql="INSERT INTO $table_threads (thread_title, forum_id, thread_poster_id, thread_poster_name, thread_last_post, thread_date)
3227              VALUES (
3228                  '".Database::escape_string($current_post['post_title'])."',
3229                  '".Database::escape_string($current_post['forum_id'])."',
3230                  '".Database::escape_string($current_post['poster_id'])."',
3231                  '".Database::escape_string($current_post['poster_name'])."',
3232                  '".Database::escape_string($values['post_id'])."',
3233                  '".Database::escape_string($current_post['post_date'])."'
3234                  )";
3235          $result=Database::query($sql, __FILE__, __LINE__);
3236          $new_thread_id=Database::insert_id();
3237          api_item_property_update($_course, TOOL_FORUM_THREAD, $new_thread_id,"visible", $current_post['poster_id']);
3238  
3239          // moving the post to the newly created thread
3240          $sql="UPDATE $table_posts SET thread_id='".Database::escape_string($new_thread_id)."', post_parent_id='0' WHERE post_id='".Database::escape_string($values['post_id'])."'";
3241          $result=Database::query($sql,__FILE__, __LINE__);
3242          //echo $sql.'<br />';
3243  
3244          // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
3245          $sql="UPDATE $table_posts SET post_parent_id='0' WHERE post_parent_id='".Database::escape_string($values['post_id'])."'";
3246          $result=Database::query($sql, __FILE__, __LINE__);
3247          //echo $sql.'<br />';
3248  
3249          // updating updating the number of threads in the forum
3250          $sql="UPDATE $table_forums SET forum_threads=forum_threads+1 WHERE forum_id='".Database::escape_string($current_post['forum_id'])."'";
3251          $result=Database::query($sql, __FILE__, __LINE__);
3252          //echo $sql.'<br />';
3253  
3254          // resetting the last post of the old thread and decreasing the number of replies and the thread
3255          $sql="SELECT * FROM $table_posts WHERE thread_id='".Database::escape_string($current_post['thread_id'])."' ORDER BY post_id DESC";
3256          //echo $sql.'<br />';
3257          $result=Database::query($sql, __FILE__, __LINE__);
3258          $row=Database::fetch_array($result);
3259          //my_print_r($row);
3260          $sql="UPDATE $table_threads SET thread_last_post='".$row['post_id']."', thread_replies=thread_replies-1 WHERE thread_id='".Database::escape_string($current_post['thread_id'])."'";
3261          $result=Database::query($sql, __FILE__, __LINE__);
3262          //echo $sql.'<br />';
3263      } else {
3264          // moving to the chosen thread
3265          $sql="UPDATE $table_posts SET thread_id='".Database::escape_string($_POST['thread'])."', post_parent_id='0' WHERE post_id='".Database::escape_string($values['post_id'])."'";
3266          $result=Database::query($sql, __FILE__, __LINE__);
3267  
3268          // resetting the parent_id of the thread to 0 for all those who had this moved post as parent
3269          $sql="UPDATE $table_posts SET post_parent_id='0' WHERE post_parent_id='".Database::escape_string($values['post_id'])."'";
3270          $result=Database::query($sql, __FILE__, __LINE__);
3271      }
3272  
3273      return get_lang('ThreadMoved');
3274  }
3275  
3276  /**
3277  *
3278  * @param
3279  * @return
3280  *
3281  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3282  * @version february 2006, dokeos 1.8
3283  */
3284  function store_move_thread($values) {
3285      global $table_posts;
3286      global $table_threads;
3287      global $table_forums;
3288      global $_course;
3289  
3290      // change the thread table: setting the forum_id to the new forum
3291      $sql="UPDATE $table_threads SET forum_id='".Database::escape_string($_POST['forum'])."' WHERE thread_id='".Database::escape_string($_POST['thread_id'])."'";
3292      $result=Database::query($sql, __FILE__, __LINE__);
3293  
3294  
3295      // changing all the posts of the thread: setting the forum_id to the new forum
3296      $sql="UPDATE $table_posts SET forum_id='".Database::escape_string($_POST['forum'])."' WHERE thread_id='".Database::escape_string($_POST['thread_id'])."'";
3297      $result=Database::query($sql, __FILE__, __LINE__);
3298  
3299      return get_lang('ThreadMoved');
3300  }
3301  
3302  
3303  /**
3304  * Prepares a string or an array of strings for display by stripping slashes
3305  * @param mixed    String or array of strings
3306  * @return mixed String or array of strings
3307  *
3308  * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
3309  * @version february 2006, dokeos 1.8
3310  */
3311  function prepare4display($input='') {
3312      $highlightcolors = array('yellow', '#33CC33','#3399CC', '#9999FF', '#33CC33');
3313      if (!is_array($input)) {
3314          if (!empty($_GET['search'])) {
3315              if (strstr($_GET['search'],'+')) {
3316                  $search_terms = explode('+',$_GET['search']);
3317              } else  {
3318                  $search_terms[] = trim($_GET['search']);
3319              }
3320              $counter = 0;
3321              foreach ($search_terms as $key=>$search_term) {
3322                  $input = str_replace(trim(api_html_entity_decode($search_term)),'<span style="background-color: '.$highlightcolors[$counter].'">'.trim(api_html_entity_decode($search_term)).'</span>',$input);
3323                  $counter++;
3324              }
3325          }
3326          return api_html_entity_decode(stripslashes($input));
3327      } else {
3328          /*foreach ($input as $key=>$value)
3329          {
3330              $returnarray[$key]=stripslashes($value);
3331          }*/
3332          $returnarray=array_walk($input, 'api_html_entity_decode');
3333          $returnarray=array_walk($input, 'stripslashes');
3334          return $returnarray;
3335      }
3336  }
3337  
3338  /**
3339   * Display the search form for the forum and display the search results
3340   *
3341   * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
3342   * @version march 2008, dokeos 1.8.5
3343   */
3344  function forum_search() {
3345      global $origin;
3346      // initiate the object
3347      $form = new FormValidator('forumsearch','post','forumsearch.php?'.api_get_cidreq().'&origin='.$origin.'');
3348  
3349      // settting the form elements
3350      $form->addElement('header', '', get_lang('ForumSearch'));
3351      $form->addElement('text', 'search_term', get_lang('SearchTerm'),'class="input_titles"');
3352      $form->applyFilter('search_term', 'html_filter');
3353      $form->addElement('static', 'search_information', '', get_lang('ForumSearchInformation')/*, $dissertation[$_GET['opleidingsonderdeelcode']]['code']*/);
3354      $form->addElement('style_submit_button', null, get_lang('Search'), 'class="search"');
3355  
3356      // setting the rules
3357      $form->addRule('search_term', get_lang('ThisFieldIsRequired'), 'required');
3358