b2evolution PHP Cross Reference Blogging Systems

Source: /inc/messaging/model/_thread.class.php - 559 lines - 17744 bytes - Summary - Text - Print

Description: This file is part of b2evolution - {@link http://b2evolution.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file is part of b2evolution - {@link http://b2evolution.net/}
   4   * See also {@link http://sourceforge.net/projects/evocms/}.
   5   *
   6   * @copyright (c)2009-2014 by Francois PLANQUE - {@link http://fplanque.net/}
   7   * Parts of this file are copyright (c)2009 by The Evo Factory - {@link http://www.evofactory.com/}.
   8   *
   9   * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}
  10   *
  11   * {@internal Open Source relicensing agreement:
  12   * The Evo Factory grants Francois PLANQUE the right to license
  13   * The Evo Factory's contributions to this file and the b2evolution project
  14   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  15   * }}
  16   *
  17   * @package messaging
  18   *
  19   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  20   * @author efy-maxim: Evo Factory / Maxim.
  21   * @author fplanque: Francois Planque.
  22   *
  23   * @version $Id: _thread.class.php 6136 2014-03-08 07:59:48Z manuel $
  24   */
  25  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  26  
  27  load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
  28  
  29  /**
  30   * Thread Class
  31   *
  32   */
  33  class Thread extends DataObject
  34  {
  35      var $title = '';
  36      var $datemodified;
  37      var $recipients = '';
  38  
  39      /**
  40       * Number unread messages
  41       * @var integer
  42       */
  43      var $num_unread_messages;
  44  
  45      /**
  46       * Recipients IDs lazy filled
  47       *
  48       * @var array
  49       */
  50      var $recipients_list;
  51  
  52  
  53      /**
  54       * Constructor
  55       * @param db_row database row
  56       */
  57  	function Thread( $db_row = NULL )
  58      {
  59          // Call parent constructor:
  60          parent::DataObject( 'T_messaging__thread', 'thrd_', 'thrd_ID', 'datemodified' );
  61  
  62          $this->delete_restrictions = array();
  63          $this->delete_cascades = array();
  64  
  65          if( $db_row != NULL )
  66          {
  67              $this->ID           = $db_row->thrd_ID;
  68              $this->title        = $db_row->thrd_title;
  69              $this->datemodified = $db_row->thrd_datemodified;
  70          }
  71          else
  72          {    // New Thread
  73              global $Session;
  74  
  75              // check if there is unsaved Thread object stored in Session
  76              $unsaved_Thread = $Session->get( 'core.unsaved_Thread' );
  77              if( !empty( $unsaved_Thread ) )
  78              {    // unsaved thread exists, delete it from Session
  79                  $Session->delete( 'core.unsaved_Thread' );
  80                  $this->title = $unsaved_Thread['title'];
  81                  $this->text = $unsaved_Thread['text'];
  82              }
  83  
  84              $logins = array();
  85  
  86              $user_login = param( 'user_login', 'string', '' );
  87              if( !empty( $user_login ) )
  88              {    // Set recipient list from $user_login
  89                  $logins[] = $user_login;
  90              }
  91              else
  92              {    // Set recipients from Contacts form
  93                  global $DB, $current_User;
  94  
  95                  $recipients = param( 'recipients', 'string', '' );
  96                  $group_ID = param( 'group_ID', 'integer', 0 );
  97  
  98                  if( !empty( $recipients ) )
  99                  {    // Selected users
 100                      $recipients = explode( ',', $recipients );
 101                      foreach( $recipients as $r => $recipient )
 102                      {
 103                          if( (int)trim( $recipient ) == 0 )
 104                          {    // remove bad data
 105                              unset( $recipients[$r] );
 106                          }
 107                      }
 108                      if( count( $recipients ) > 0 )
 109                      {
 110                          $SQL = new SQL();
 111                          $SQL->SELECT( 'user_ID, user_login' );
 112                          $SQL->FROM( 'T_messaging__contact' );
 113                          $SQL->FROM_add( 'LEFT JOIN T_users ON mct_to_user_ID = user_ID' );
 114                          $SQL->WHERE( 'mct_from_user_ID = '.$current_User->ID );
 115                          $SQL->WHERE_and( 'mct_to_user_ID IN ('.implode( ',', $recipients ).')' );
 116                          // asimo> If A user block B user it means that A user doesn't want to receive private message from B,
 117                          // but A user still should be able to send a message to B.
 118                          //$SQL->WHERE_and( 'mct_blocked = 0' );
 119                          $SQL->ORDER_BY( 'user_login' );
 120  
 121                          $logins = $DB->get_assoc( $SQL->get() );
 122                      }
 123                  }
 124                  else if( $group_ID > 0 )
 125                  {    // All users from one group
 126                      $SQL = new SQL();
 127                      $SQL->SELECT( 'user_ID, user_login' );
 128                      $SQL->FROM( 'T_messaging__contact_groupusers' );
 129                      $SQL->FROM_add( 'LEFT JOIN T_users ON cgu_user_ID = user_ID' );
 130                      $SQL->FROM_add( 'LEFT JOIN T_messaging__contact_groups ON cgu_cgr_ID = cgr_ID' );
 131                      $SQL->FROM_add( 'LEFT JOIN T_messaging__contact ON mct_from_user_ID = cgr_user_ID AND mct_to_user_ID = user_ID' );
 132                      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
 133                      $SQL->WHERE_and( 'cgr_ID = '.$DB->quote( $group_ID ) );
 134                      // asimo> If A user block B user it means that A user doesn't want to receive private message from B,
 135                      // but A user still should be able to send a message to B.
 136                      //$SQL->WHERE_and( 'mct_blocked = 0' );
 137                      $SQL->ORDER_BY( 'user_login' );
 138  
 139                      $logins = $DB->get_assoc( $SQL->get() );
 140                  }
 141              }
 142  
 143              $this->recipients = implode( ', ', $logins );
 144  
 145              if( !empty( $logins ) )
 146              {    // Set this var to initialize the preselected users for fbautocomplete jQuery plugin
 147                  global $recipients_selected;
 148                  foreach( $logins as $user_ID => $user_login )
 149                  {
 150                      $recipients_selected[] = array(
 151                          'id'    => $user_ID,
 152                          'title' => $user_login
 153                      );
 154                  }
 155              }
 156          }
 157      }
 158  
 159  
 160      /**
 161       * Load data from Request form fields.
 162       * @return boolean true if loaded data seems valid.
 163       */
 164  	function load_from_Request()
 165      {
 166          global $thrd_recipients, $thrd_recipients_array;
 167  
 168          // Resipients
 169          $this->set_string_from_param( 'recipients', empty( $thrd_recipients_array ) ? true : false );
 170  
 171          // Title
 172          param( 'thrd_title', 'string' );
 173          param_check_not_empty( 'thrd_title', T_('Please enter a subject') );
 174          $this->set_from_Request( 'title', 'thrd_title' );
 175  
 176          // Message
 177          param_check_not_empty( 'msg_text', T_('Please enter a message') );
 178  
 179          $this->param_check__recipients( 'thrd_recipients', $thrd_recipients, $thrd_recipients_array );
 180  
 181          return ! param_errors_detected();
 182      }
 183  
 184  
 185      /**
 186       * Set param value
 187       *
 188       * By default, all values will be considered strings
 189       *
 190       * @param string parameter name
 191       * @param mixed parameter value
 192       * @param boolean true to set to NULL if empty value
 193       * @return boolean true, if a value has been set; false if it has not changed
 194       */
 195  	function set( $parname, $parvalue, $make_null = false )
 196      {
 197          switch( $parname )
 198          {
 199              case 'recipients':
 200                  $this->recipients = $parvalue;
 201                  break;
 202              case 'title':
 203              default:
 204                  return $this->set_param( $parname, 'string', $parvalue, $make_null );
 205          }
 206      }
 207  
 208  
 209      /**
 210       * Check if recipients available in database
 211       *
 212       * @param string Input name
 213       * @param string Recipients logins separated with comma (Used for browsers without JavaScript)
 214       * @param string Recipients logins in array format (Used with jQuery plugin fbautocomplete)
 215       * @return boolean true if all recipients allow the current User to contact them, false otherwise
 216       */
 217  	function param_check__recipients( $var, $recipients, $recipients_array )
 218      {
 219          global $DB, $current_User, $UserSettings, $Messages;
 220  
 221          if( !empty( $recipients_array ) )
 222          {    // These data is created by jQuery plugin fbautocomplete
 223              $recipients_list = $recipients_array['title'];
 224          }
 225          else
 226          {    // For browsers without JavaScript
 227              // split recipients into array using comma separator
 228              $recipients_list = array();
 229              $recipients = trim( str_replace( ',', ' ', $recipients ) );
 230              foreach( explode(' ', $recipients) as $recipient )
 231              {
 232                  $login = trim($recipient);
 233                  if( ! empty( $login ) )
 234                  {
 235                      $recipients_list[] = evo_strtolower( $login );
 236                  }
 237              }
 238          }
 239  
 240          $recipients_list = array_unique( $recipients_list );
 241  
 242          $error_msg = '';
 243  
 244          // check has recipients list login of current user
 245          if( in_array( $current_User->login, $recipients_list ) )
 246          {
 247              $error_msg = sprintf( T_( 'You cannot send threads to yourself: %s' ), $current_User->login );
 248          }
 249  
 250          // load recipient User objects
 251          $UserCache = & get_UserCache();
 252          $UserCache->load_where( 'user_login IN ( "'.implode( '","', $recipients_list ).'" )' );
 253  
 254          // check are recipients available in database
 255          $this->recipients_list = array();
 256          $unavailable_recipients_list = array();
 257          $closed_recipients_list = array();
 258          $status_restricted_recipients = array();
 259          $recipients_without_perm = array();
 260          $recipients_restricted_pm = array();
 261          // check if recipient user enable private messages only if sender user doesn't have 'delete' messaging permission
 262          $check_enable_pm = !$current_User->check_perm( 'perm_messaging', 'delete' );
 263          foreach( $recipients_list as $recipient )
 264          {
 265              $recipient_User = $UserCache->get_by_login( $recipient, false );
 266              if( $recipient_User === false )
 267              { // user doesn't exists
 268                  $unavailable_recipients_list[] = $recipient;
 269                  continue;
 270              }
 271  
 272              if( !$recipient_User->check_status( 'can_receive_pm' ) )
 273              { // user status restrict to receive private messages
 274                  if( $recipient_User->check_status( 'is_closed' ) )
 275                  { // user account was closed
 276                      $closed_recipients_list[] = $recipient;
 277                      continue;
 278                  }
 279  
 280                  $status_restricted_recipients[] = $recipient;
 281                  continue;
 282              }
 283  
 284              if( !$recipient_User->check_perm( 'perm_messaging', 'reply' ) )
 285              { // user doesn't have permission to read private messages
 286                  $recipients_without_perm[] = $recipient;
 287                  continue;
 288              }
 289  
 290              if( !$UserSettings->get( 'enable_PM', $recipient_User->ID ) )
 291              { // recipient doesn't want to receive private messages
 292                  $recipients_restricted_pm[] = $recipient;
 293                  if( $check_enable_pm )
 294                  { // sender is not a user with delete ( "admin" ) messaging permission, so this user can't be in the recipients list
 295                      continue;
 296                  }
 297              }
 298  
 299              // recipient is correct, add to recipient list
 300              $this->recipients_list[] = $recipient_User->ID;
 301          }
 302  
 303          if ( count( $unavailable_recipients_list ) > 0 )
 304          {
 305              if ( ! empty( $error_msg ) )
 306              {
 307                  $error_msg .= '<br />';
 308              }
 309              $error_msg .= sprintf( 'The following users were not found: %s', implode( ', ', $unavailable_recipients_list ) );
 310          }
 311  
 312          if ( count( $closed_recipients_list ) > 0 )
 313          {
 314              if ( ! empty( $error_msg ) )
 315              {
 316                  $error_msg .= '<br />';
 317              }
 318              $error_msg .= sprintf( 'The following users no longer exist: %s', implode( ', ', $closed_recipients_list ) );
 319          }
 320  
 321          if ( count( $status_restricted_recipients ) > 0 )
 322          {
 323              if ( ! empty( $error_msg ) )
 324              {
 325                  $error_msg .= '<br />';
 326              }
 327              $error_msg .= sprintf( 'The following users status currently does not permit to receive private messages: %s', implode( ', ', $status_restricted_recipients ) );
 328          }
 329  
 330          if ( count( $recipients_without_perm ) > 0 )
 331          {
 332              if ( ! empty( $error_msg ) )
 333              {
 334                  $error_msg .= '<br />';
 335              }
 336              $error_msg .= sprintf( 'The following users have no permission to read private messages: %s', implode( ', ', $recipients_without_perm ) );
 337          }
 338  
 339          $restricted_pm_count = count( $recipients_restricted_pm );
 340          if ( $restricted_pm_count > 0 )
 341          { // there is at least one recipient who doesn't want to receive private messages
 342              if( $check_enable_pm )
 343              { // sender is not a user with delete ( "admin" ) messaging permission, so this user can't be in the recipients list
 344                  if ( ! empty( $error_msg ) )
 345                  {
 346                      $error_msg .= '<br />';
 347                  }
 348                  $error_msg .= sprintf( 'The following users don\'t want to receive private messages: %s', implode( ', ', $recipients_restricted_pm ) );
 349              }
 350              else
 351              { // send is an admin
 352                  $manual_link = get_manual_link( 'messaging', T_( 'See manual' ).'.' );
 353                  if( $restricted_pm_count > 1 )
 354                  { // more then one recipient don't want to receive private messages
 355                      $note = sprintf( T_( 'Users &laquo;%s&raquo; do not allow receiving private messages. Message has been sent anyway because you are an administrator.' ), implode( ', ', $recipients_restricted_pm ) );
 356                  }
 357                  else
 358                  { // one recipient doesn't want to receive private messages
 359                      $note = sprintf( T_( 'User &laquo;%s&raquo; does not allow receiving private messages. Message has been sent anyway because you are an administrator.' ), $recipients_restricted_pm[0] );
 360                  }
 361                  // add note
 362                  $Messages->add( $note.$manual_link, 'note' );
 363              }
 364          }
 365  
 366          // Here we select those recipients who has blocked the sender. Note that users with 'delete' messaging permission can't be blocked!
 367          $blocked_contacts = check_blocked_contacts( $this->recipients_list );
 368          if( !empty( $blocked_contacts ) )
 369          { // There is at least one blocked recipient
 370              if ( ! empty( $error_msg ) )
 371              {
 372                  $error_msg .= '<br />';
 373              }
 374              $error_msg .= T_( 'The following users don\'t want you to contact them at this time: ' ).' '.implode( ', ', $blocked_contacts );
 375          }
 376  
 377          if( empty( $error_msg ) )
 378          { // no errors yet
 379              $recipients_count = count( $recipients_list );
 380              if( ( $recipients_count > 1 ) && ( param( 'thrdtype', 'string', 'discussion' ) != 'discussion' ) )
 381              { // user want's to send more then one individual messages, check if is allowed
 382                  list( $max_new_threads, $new_threads_count ) = get_todays_thread_settings();
 383                  if( ( !empty( $max_new_threads ) ) && ( ( $max_new_threads - $new_threads_count ) < $recipients_count ) )
 384                  { // user has a create thread limit, and recipients number exceed that limit
 385                      $error_msg .= '<br />';
 386                      $error_msg .= sprintf( T_( 'You are unable to send %d individual messages, because it exceeds your remaining daily limit of %d.' ), $recipients_count, $max_new_threads - $new_threads_count );
 387                  }
 388              }
 389          }
 390  
 391          if( ! empty( $error_msg ) )
 392          {    // show error
 393              param_error( $var, $error_msg );
 394              return false;
 395          }
 396  
 397          return true;
 398      }
 399  
 400  
 401      /**
 402       * Delete thread and dependencies from database
 403       */
 404  	function dbdelete()
 405      {
 406          global $DB;
 407  
 408          if( $this->ID == 0 ) debug_die( 'Non persistant object cannot be deleted!' );
 409  
 410          $DB->begin();
 411  
 412          // Delete Messages
 413          $ret = $DB->query( 'DELETE FROM T_messaging__message
 414                                                  WHERE msg_thread_ID='.$this->ID );
 415          // Delete Statuses
 416          $ret = $DB->query( 'DELETE FROM T_messaging__threadstatus
 417                                                  WHERE tsta_thread_ID='.$this->ID );
 418          // Delete Thread
 419          if( ! parent::dbdelete() )
 420          {
 421              $DB->rollback();
 422  
 423              return false;
 424          }
 425  
 426          $DB->commit();
 427  
 428          return true;
 429      }
 430  
 431  
 432      /**
 433       * Load recipients of the current thread
 434       *
 435       * @return recipients list
 436       */
 437  	function load_recipients()
 438      {
 439          global $DB;
 440  
 441          if( empty( $this->recipients_list ) && ( !empty( $this->ID ) ) )
 442          {
 443              $SQL = new SQL();
 444              $SQL->SELECT( 'tsta_user_ID' );
 445              $SQL->FROM( 'T_messaging__threadstatus' );
 446              $SQL->WHERE( 'tsta_thread_ID = '.$this->ID );
 447  
 448              $this->recipients_list = array();
 449              foreach( $DB->get_results( $SQL->get() ) as $row )
 450              {
 451                  $this->recipients_list[] = $row->tsta_user_ID;
 452              }
 453          }
 454  
 455          return $this->recipients_list;
 456      }
 457  
 458  
 459      /**
 460       * Check permission on a persona
 461       *
 462       * @return boolean true if granted
 463       */
 464  	function check_perm( $action, $assert = true )
 465      {
 466          global $current_User;
 467  
 468          return $current_User->check_perm( 'perm_messaging', $action, $assert );
 469      }
 470  
 471  
 472      /**
 473       * Check if user is recipient of the current thread
 474       *
 475       * @param user ID
 476       * @return boolean true if user is recipient, false otherwise
 477       */
 478  	function check_thread_recipient( $user_ID )
 479      {
 480          $this->load_recipients();
 481          return in_array( $user_ID, $this->recipients_list );
 482      }
 483  
 484  
 485      /**
 486       * Check if current User is allowed to reply on this thread.
 487       * Users are allowed to reply only to those threads where they are involved and there is at least one user between the recipients who didn't block the User.
 488       * Note: Currently it doesn't matter if the sender is in the recipients user's contact list or not except in that case when the sender is blocked.
 489       *
 490       * @return boolean true if current User is allowed, false otherwise
 491       */
 492  	function check_allow_reply()
 493      {
 494          global $DB, $current_User;
 495  
 496          // load thread recipients
 497          $this->load_recipients();
 498  
 499          // check if user is involved in recipients list
 500          if( ! $this->check_thread_recipient( $current_User->ID ) )
 501          { // Deny to write a new reply for not involved users
 502              // asimo> We may call debug_die() here because this is not a correct state of the application
 503              param_error( '', T_('You cannot post a message in a thread you\'re not involved in.') );
 504              return false;
 505          }
 506  
 507          // check if all of the recipients are closed
 508          $UserCache = & get_UserCache();
 509          $UserCache->load_where( 'user_ID IN ( '.implode( ',', $this->recipients_list ).' )' );
 510          $all_closed = true;
 511          foreach( $this->recipients_list as $recipient_ID )
 512          {
 513              if( $recipient_ID == $current_User->ID )
 514              { // skip current User
 515                  continue;
 516              }
 517              $recipient_User = $UserCache->get_by_ID( $recipient_ID, false );
 518              if( $recipient_User && $recipient_User->check_status( 'can_receive_pm' ) )
 519              { // this recipient exists and status allows to receive private messages
 520                  $all_closed = false;
 521                  break;
 522              }
 523          }
 524          if( $all_closed )
 525          { // all recipients are closed or deleted
 526              param_error( '', T_( 'You cannot reply because all the other users involved in this conversation have closed their account.' ) );
 527              return false;
 528          }
 529  
 530          if( $current_User->check_perm( 'perm_messaging', 'delete' ) )
 531          { // users with delete permission are always able to reply to a conversation where they are involved
 532              return true;
 533          }
 534  
 535          $SQL = new SQL();
 536  
 537          $SQL->SELECT( 'count( ts.tsta_user_ID )' );
 538          $SQL->FROM( 'T_messaging__threadstatus ts
 539                                  LEFT JOIN T_messaging__contact mc ON ts.tsta_user_ID = mc.mct_from_user_ID
 540                                              AND mc.mct_to_user_ID = '.$current_User->ID );
 541          // don't select current User
 542          $SQL->WHERE( 'ts.tsta_user_ID <> '.$current_User->ID );
 543          // restrict to the given thread
 544          $SQL->WHERE_and( 'ts.tsta_thread_ID ='.$this->ID );
 545          // sender is not blocked or is not present in all recipient's contact list
 546          $SQL->WHERE_and( '( mc.mct_blocked IS NULL OR mc.mct_blocked = 0 )' );
 547  
 548          if( $DB->get_var( $SQL->get(), 0, NULL, 'Count all users whou are involved in the given thread but not the current User and didn\'t block the current User' ) > 0 )
 549          { // there is at least one recipient who accept the reply
 550              return true;
 551          }
 552  
 553          // all recipients have blocked the current User
 554          param_error( '', T_( 'The recipient(s) do not want you to contact them at this time.' ) );
 555          return false;
 556      }
 557  }
 558  
 559  ?>

title

Description

title

Description

title

Description

title

title

Body