Skip to:
Content

Ticket #7523: 7523.01.patch

File 7523.01.patch, 13.9 KB (added by r-a-y, 13 months ago)
  • src/bp-messages/bp-messages-functions.php

     
    550550        return $retval;
    551551}
    552552
    553 /** Email *********************************************************************/
     553/** Hooks *********************************************************************/
     554
     555/**
     556 * Delete all message threads that the deleted user has sent.
     557 *
     558 * @since 2.9.0
     559 *
     560 * @param int $user_id The deleted user ID.
     561 */
     562function bp_messages_delete_threads_on_user_delete( $user_id ) {
     563        $threads = BP_Messages_Thread::get_current_threads_for_user( array(
     564                'user_id'     => $user_id,
     565                'box'         => 'sentbox',
     566                'deleted'     => null,
     567                'fields'      => 'ids',
     568                'count_total' => false
     569        ) );
     570
     571        if ( empty( $threads ) ) {
     572                return;
     573        }
     574
     575        foreach ( $threads['threads'] as $thread_id ) {
     576                BP_Messages_Thread::delete( $thread_id, $user_id, true );
     577        }
     578}
     579add_action( 'deleted_user', 'bp_messages_delete_threads_on_user_delete' );
    554580
    555581/**
    556582 * Email message recipients to alert them of a new unread private message.
  • src/bp-messages/classes/class-bp-messages-thread.php

     
    328328         * @since 1.0.0
    329329         * @since 2.7.0 The $user_id parameter was added. Previously the current user
    330330         *              was always assumed.
    331          *
    332          * @param int $thread_id The message thread ID.
    333          * @param int $user_id The ID of the user in the thread to mark messages as
    334          *                     deleted for. Defaults to the current logged-in user.
    335          *
     331         * @since 2.9.0 Added $force as a parameter.
     332         *
     333         * @param int  $thread_id The message thread ID.
     334         * @param int  $user_id   The ID of the user in the thread to mark messages as deleted for. Defaults
     335         *                        to the current logged-in user.
     336         * @param bool $force     Whether to delete the entire message thread for all recipients. If false,
     337         *                        every recipient in a thread needs to mark the thread as deleted before the
     338         *                        thread is deleted from the DB. Default: false.
    336339         * @return bool
    337340         */
    338         public static function delete( $thread_id = 0, $user_id = 0 ) {
     341        public static function delete( $thread_id = 0, $user_id = 0, $force = false ) {
    339342                global $wpdb;
    340343
    341                 $thread_id = (int) $thread_id;
    342                 $user_id = (int) $user_id;
     344                $thread_id  = (int) $thread_id;
     345                $user_id    = (int) $user_id;
    343346
    344347                if ( empty( $user_id ) ) {
    345348                        $user_id = bp_loggedin_user_id();
     
    358361
    359362                $bp = buddypress();
    360363
    361                 // Mark messages as deleted
    362                 $wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, $user_id ) );
    363 
    364364                // Get the message ids in order to pass to the action.
    365365                $message_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_messages} WHERE thread_id = %d", $thread_id ) );
    366366
    367                 // Check to see if any more recipients remain for this message.
    368                 $recipients = $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d AND is_deleted = 0", $thread_id ) );
     367                // Do the following when a user manually deletes a thread.
     368                if ( false === $force ) {
     369                        // Mark messages as deleted
     370                        $wpdb->query( $wpdb->prepare( "UPDATE {$bp->messages->table_name_recipients} SET is_deleted = 1 WHERE thread_id = %d AND user_id = %d", $thread_id, $user_id ) );
     371
     372                        // Check to see if any more recipients remain for this message.
     373                        $recipients = $wpdb->get_results( $wpdb->prepare( "SELECT id FROM {$bp->messages->table_name_recipients} WHERE thread_id = %d AND is_deleted = 0", $thread_id ) );
     374                }
    369375
    370376                // No more recipients so delete all messages associated with the thread.
    371                 if ( empty( $recipients ) ) {
     377                if ( true === $force || ( false === $force && isset( $recipients ) && empty( $recipients ) ) ) {
    372378
    373379                        /**
    374380                         * Fires before an entire message thread is deleted.
     
    422428         * Get current message threads for a user.
    423429         *
    424430         * @since 1.0.0
     431         * @since 2.9.0 Added $deleted, $fields and $count_total as parameters to $args.
    425432         *
    426433         * @param array $args {
    427434         *     Array of arguments.
    428          *     @type int    $user_id      The user ID.
    429          *     @type string $box          The type of mailbox to get. Either 'inbox' or 'sentbox'.
    430          *                                Defaults to 'inbox'.
    431          *     @type string $type         The type of messages to get. Either 'all' or 'unread'
    432          *                                or 'read'. Defaults to 'all'.
    433          *     @type int    $limit        The number of messages to get. Defaults to null.
    434          *     @type int    $page         The page number to get. Defaults to null.
    435          *     @type string $search_terms The search term to use. Defaults to ''.
    436          *     @type array  $meta_query   Meta query arguments. See WP_Meta_Query for more details.
     435         *     @type int      $user_id      The user ID.
     436         *     @type string   $box          The type of mailbox to get. Either 'inbox' or 'sentbox'.
     437         *                                  Defaults to 'inbox'.
     438         *     @type string   $type         The type of messages to get. Either 'all' or 'unread'
     439         *                                  or 'read'. Defaults to 'all'.
     440         *     @type int      $limit        The number of messages to get. Defaults to null.
     441         *     @type int      $page         The page number to get. Defaults to null.
     442         *     @type string   $search_terms The search term to use. Defaults to ''.
     443         *     @type array    $meta_query   Meta query arguments. See WP_Meta_Query for more details.
     444         *     @type int|null $deleted      Whether to fetch deleted messages. 0 means we will not fetch deleted
     445         *                                  messages; 1 means we will. null means we will not query for deleted
     446         *                                  messages. Default: 0.
     447         *     @type string   $fields       Thread fields to retrieve. 'all' to fetch entire thread objects, 'ids' to
     448         *                                  get only the message thread IDs. DefaultL 'all'.
     449         *     @type bool     $count_total  If true, an additional DB query is run to count the total message threads
     450         *                                  for the query. Default: true.
    437451         * }
    438452         * @return array|bool Array on success. Boolean false on failure.
    439453         */
     
    463477                        'limit'        => null,
    464478                        'page'         => null,
    465479                        'search_terms' => '',
    466                         'meta_query'   => array()
     480                        'meta_query'   => array(),
     481                        'deleted'      => 0,
     482                        'fields'       => 'all',
     483                        'count_total'  => true
    467484                ) );
    468485
    469                 $pag_sql = $type_sql = $search_sql = $user_id_sql = $sender_sql = '';
    470                 $meta_query_sql = array(
    471                         'join'  => '',
    472                         'where' => ''
    473                 );
     486                $pag_sql = $meta_query_join_sql = '';
     487                $where   = array();
    474488
    475489                if ( $r['limit'] && $r['page'] ) {
    476490                        $pag_sql = $wpdb->prepare( " LIMIT %d, %d", intval( ( $r['page'] - 1 ) * $r['limit'] ), intval( $r['limit'] ) );
    477491                }
    478492
    479493                if ( $r['type'] == 'unread' ) {
    480                         $type_sql = " AND r.unread_count != 0 ";
     494                        $where['type'] = "r.unread_count != 0 ";
    481495                } elseif ( $r['type'] == 'read' ) {
    482                         $type_sql = " AND r.unread_count = 0 ";
     496                        $where['type'] = "r.unread_count = 0 ";
    483497                }
    484498
    485499                if ( ! empty( $r['search_terms'] ) ) {
    486500                        $search_terms_like = '%' . bp_esc_like( $r['search_terms'] ) . '%';
    487                         $search_sql        = $wpdb->prepare( "AND ( subject LIKE %s OR message LIKE %s )", $search_terms_like, $search_terms_like );
     501                        $where['search']   = $wpdb->prepare( "( subject LIKE %s OR message LIKE %s )", $search_terms_like, $search_terms_like );
    488502                }
    489503
    490504                $r['user_id'] = (int) $r['user_id'];
    491505
    492                 // Default deleted SQL.
    493                 $deleted_sql = 'r.is_deleted = 0';
     506                // Deleted SQL.
     507                if ( is_int( $r['deleted'] ) ) {
     508                        $where['delete'] = $wpdb->prepare( "r.is_deleted = %d", $r['deleted'] );
     509                }
    494510
    495511                switch ( $r['box'] ) {
    496512                        case 'sentbox' :
    497                                 $user_id_sql = 'AND ' . $wpdb->prepare( 'm.sender_id = %d', $r['user_id'] );
    498                                 $sender_sql  = 'AND m.sender_id = r.user_id';
     513                                $where['user_id'] = $wpdb->prepare( 'm.sender_id = %d', $r['user_id'] );
     514                                $where['sender']  = 'm.sender_id = r.user_id';
    499515                                break;
    500516
    501517                        case 'inbox' :
    502                                 $user_id_sql = 'AND ' . $wpdb->prepare( 'r.user_id = %d', $r['user_id'] );
    503                                 $sender_sql  = 'AND r.sender_only = 0';
     518                                $where['user_id'] = $wpdb->prepare( 'r.user_id = %d', $r['user_id'] );
     519                                $where['sender']  = 'r.sender_only = 0';
    504520                                break;
    505521
    506522                        default :
    507523                                // Omit user-deleted threads from all other custom message boxes.
    508                                 $deleted_sql = $wpdb->prepare( '( r.user_id = %d AND r.is_deleted = 0 )', $r['user_id'] );
     524                                $where['custom_box'] = $wpdb->prepare( '( r.user_id = %d AND r.is_deleted = 0 )', $r['user_id'] );
    509525                                break;
    510526                }
    511527
    512528                // Process meta query into SQL.
    513529                $meta_query = self::get_meta_query_sql( $r['meta_query'] );
    514530                if ( ! empty( $meta_query['join'] ) ) {
    515                         $meta_query_sql['join'] = $meta_query['join'];
     531                        $meta_query_join_sql = $meta_query['join'];
    516532                }
    517533                if ( ! empty( $meta_query['where'] ) ) {
    518                         $meta_query_sql['where'] = $meta_query['where'];
     534                        // Strips leading AND; also see BP_Groups_Group::strip_leading_and().
     535                        $where['meta_query'] = preg_replace( '/^\s*AND\s*/', '', $meta_query['where'] );
    519536                }
    520537
    521538                $bp = buddypress();
    522539
    523540                // Set up SQL array.
    524541                $sql = array();
    525                 $sql['select'] = 'SELECT m.thread_id, MAX(m.date_sent) AS date_sent';
    526                 $sql['from']   = "FROM {$bp->messages->table_name_recipients} r INNER JOIN {$bp->messages->table_name_messages} m ON m.thread_id = r.thread_id {$meta_query_sql['join']}";
    527                 $sql['where']  = "WHERE {$deleted_sql} {$user_id_sql} {$sender_sql} {$type_sql} {$search_sql} {$meta_query_sql['where']}";
    528                 $sql['misc']   = "GROUP BY m.thread_id ORDER BY date_sent DESC {$pag_sql}";
     542                if ( 'ids' === $r['fields'] ) {
     543                        $sql['select'] = 'SELECT m.thread_id';
     544                } else {
     545                        $sql['select'] = 'SELECT m.thread_id, MAX(m.date_sent) AS date_sent';
     546                }
     547                $sql['from']  = "FROM {$bp->messages->table_name_recipients} r INNER JOIN {$bp->messages->table_name_messages} m ON m.thread_id = r.thread_id {$meta_query_join_sql}";
     548                $sql['where'] = 'WHERE ' . join( ' AND ', $where );
     549                $sql['misc']  = "GROUP BY m.thread_id ORDER BY date_sent DESC {$pag_sql}";
    529550
    530551                // Get thread IDs.
    531                 $thread_ids = $wpdb->get_results( implode( ' ', $sql ) );
     552                if ( 'ids' === $r['fields'] ) {
     553                        $thread_ids = $wpdb->get_col( implode( ' ', $sql ) );
     554                } else {
     555                        $thread_ids = $wpdb->get_results( implode( ' ', $sql ) );
     556                }
    532557                if ( empty( $thread_ids ) ) {
    533558                        return false;
    534559                }
    535560
    536561                // Adjust $sql to work for thread total.
    537                 $sql['select'] = 'SELECT COUNT( DISTINCT m.thread_id )';
    538                 unset( $sql['misc'] );
    539                 $total_threads = $wpdb->get_var( implode( ' ', $sql ) );
     562                $total_threads = null;
     563                if ( true === $r['count_total'] ) {
     564                        $sql['select'] = 'SELECT COUNT( DISTINCT m.thread_id )';
     565                        unset( $sql['misc'] );
     566                        $total_threads = $wpdb->get_var( implode( ' ', $sql ) );
     567                }
     568
     569                if ( 'all' === $r['fields'] ) {
     570                        // Sort threads by date_sent.
     571                        foreach( (array) $thread_ids as $thread ) {
     572                                $sorted_threads[ $thread->thread_id ] = strtotime( $thread->date_sent );
     573                        }
    540574
    541                 // Sort threads by date_sent.
    542                 foreach( (array) $thread_ids as $thread ) {
    543                         $sorted_threads[ $thread->thread_id ] = strtotime( $thread->date_sent );
     575                        arsort( $sorted_threads );
     576
     577                        $threads = array();
     578                        foreach ( (array) $sorted_threads as $thread_id => $date_sent ) {
     579                                $threads[] = new BP_Messages_Thread( $thread_id, 'ASC', array(
     580                                        'update_meta_cache' => false
     581                                ) );
     582                        }
    544583                }
    545584
    546                 arsort( $sorted_threads );
     585                // Set up return value.
     586                if ( 'all' === $r['fields'] ) {
     587                        $threads = &$threads;
     588                } else {
     589                        $threads = $thread_ids;
     590                }
     591                $retval = array( 'threads' => $threads );
    547592
    548                 $threads = array();
    549                 foreach ( (array) $sorted_threads as $thread_id => $date_sent ) {
    550                         $threads[] = new BP_Messages_Thread( $thread_id, 'ASC', array(
    551                                 'update_meta_cache' => false
    552                         ) );
     593                if ( null !== $total_threads ) {
     594                        $retval['total'] = (int) $total_threads;
    553595                }
    554596
    555597                /**
     
    558600                 * @since 2.2.0
    559601                 *
    560602                 * @param array $value {
    561                  *     @type array $threads       Array of threads. Passed by reference.
    562                  *     @type int   $total_threads Number of threads found by the query.
     603                 *     @type array $threads       Array of threads. Passed by reference if 'fields' is 'all' in the query.
     604                 *     @type int   $total_threads Number of threads found by the query. This is added as an array key if
     605                 *                                'count_total' is true in the query.
    563606                 * }
    564607                 */
    565                 return apply_filters( 'bp_messages_thread_current_threads', array(
    566                         'threads' => &$threads,
    567                         'total'   => (int) $total_threads
    568                 ) );
     608                return apply_filters( 'bp_messages_thread_current_threads', $retval );
    569609        }
    570610
    571611        /**
  • tests/phpunit/testcases/messages/template.php

     
    359359
    360360                $_REQUEST = $request;
    361361        }
     362
     363        /**
     364         * @group delete
     365         * @group BP_Messages_Box_Template
     366         */
     367        public function test_bp_messages_template_should_not_have_threads_by_deleted_user() {
     368                $u1 = $this->factory->user->create();
     369                $u2 = $this->factory->user->create();
     370                $u3 = $this->factory->user->create();
     371
     372                // create initial thread
     373                $this->factory->message->create( array(
     374                        'sender_id'  => $u2,
     375                        'recipients' => array( $u1 ),
     376                ) );
     377
     378                // create some threads by our deleted user
     379                $this->factory->message->create_many( 3, array(
     380                        'sender_id'  => $u3,
     381                        'recipients' => array( $u1 ),
     382                ) );
     383
     384                // Delete user 3.
     385                if ( is_multisite() ) {
     386                        wpmu_delete_user( $u3 );
     387                } else {
     388                        wp_delete_user( $u3 );
     389                }
     390
     391                // Only the initial thread should remain.
     392                $threads = new BP_Messages_Box_Template( array(
     393                        'user_id' => $u1
     394                ) );
     395                $this->assertEquals( 1, $threads->thread_count );
     396        }
    362397}