Skip to:
Content

BuddyPress.org

Changeset 8251


Ignore:
Timestamp:
04/08/2014 06:55:30 AM (6 years ago)
Author:
imath
Message:

Insert a new "since" filter for the activity stream to be used by HeartBeat check feature

In rare cases, the field date_recorded of the activity table can be updated to a date greater than the most recent activity in terms of id.
The Heartbeat feature was based on the id field so far, while the activity stream is sorting items according to the date_recorded field. As a result, in this very particular case, activities with an id greater than the activity (which date has been updated) will be loaded again in the stream and this until a new activity is published.
To prevent this to happen, we introduce this new "since" filter to be used by the HeartBeat feature once it gets the timestamp of the most recent activity displayed in the stream.

props SGr33n, boonebgorges, imath

Fixes #5505

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-activity/bp-activity-classes.php

    r8249 r8251  
    11901190     *
    11911191     * @param array $filter_array {
    1192      *     Fields and values to filter by. Each can be either a single
    1193      *     string, a comma-separated list, or an array of values.
     1192     *     Fields and values to filter by.
    11941193     *     @type array|string|id $user_id User ID(s).
    11951194     *     @type array|string $object Corresponds to the 'component'
     
    12011200     *     @type array|string|int $secondary_id Corresponds to the
    12021201     *           'secondary_item_id' column in the database.
     1202     *     @type int $offset Return only those items with an ID greater
     1203     *           than the offset value.
     1204     *     @type string $since Return only those items that have a
     1205     *           date_recorded value greater than a given MySQL-formatted
     1206     *           date.
    12031207     * }
    12041208     * @return string The filter clause, for use in a SQL query.
     
    12411245            $sid_sql = absint( $filter_array['offset'] );
    12421246            $filter_sql[] = "a.id >= {$sid_sql}";
     1247        }
     1248
     1249        if ( ! empty( $filter_array['since'] ) ) {
     1250            // Validate that this is a proper Y-m-d H:i:s date
     1251            // Trick: parse to UNIX date then translate back
     1252            $translated_date = date( 'Y-m-d H:i:s', strtotime( $filter_array['since'] ) );
     1253            if ( $translated_date === $filter_array['since'] ) {
     1254                $filter_sql[] = "a.date_recorded > '{$translated_date}'";
     1255            }
    12431256        }
    12441257
  • trunk/bp-activity/bp-activity-filters.php

    r8219 r8251  
    430430    $bp = buddypress();
    431431
    432     if ( ! empty( $bp->activity->new_update_id ) && $bp->activity->new_update_id == bp_get_activity_id() ) {
     432    if ( ! empty( $bp->activity->last_recorded ) && $bp->activity->last_recorded == bp_get_activity_date_recorded() ) {
    433433        $classes .= ' new-update';
    434434    }
     
    439439
    440440/**
     441 * Check if Activity Heartbeat feature i on to add a timestamp class.
     442 *
     443 * @since BuddyPress (2.0.0)
     444 *
     445 * @param string $classes
     446 * @return string $classes
     447 */
     448function bp_activity_timestamp_class( $classes = '' ) {
     449
     450    if ( ! bp_activity_do_heartbeat() ) {
     451        return $classes;
     452    }
     453
     454    $activity_date = bp_get_activity_date_recorded();
     455
     456    if ( empty( $activity_date ) ) {
     457        return $classes;
     458    }
     459   
     460    $classes .= ' date-recorded-' . strtotime( $activity_date );
     461
     462    return $classes;
     463}
     464add_filter( 'bp_get_activity_css_class', 'bp_activity_timestamp_class', 9, 1 );
     465
     466/**
    441467 * Use WordPress Heartbeat API to check for latest activity update.
    442468 *
     
    444470 *
    445471 * @uses bp_activity_get_last_updated() to get the recorded date of the last activity
    446 
     472 *
    447473 * @param array $response
    448474 * @param array $data
     
    452478    $bp = buddypress();
    453479
    454     if ( empty( $data['bp_activity_last_id'] ) ) {
     480    if ( empty( $data['bp_activity_last_recorded'] ) ) {
    455481        return $response;
    456482    }
     
    460486    $activity_latest_args = bp_parse_args(
    461487        bp_ajax_querystring( 'activity' ),
    462         array( 'offset' => absint( $data['bp_activity_last_id'] ) + 1 ),
     488        array( 'since' => date( 'Y-m-d H:i:s', $data['bp_activity_last_recorded'] ) ),
    463489        'activity_latest_args'
    464490    );
    465491
    466492    $newest_activities = array();
    467     $last_activity_id = 0;
     493    $last_activity_recorded = 0;
    468494
    469495    // Temporarly add a just-posted class for new activity items
     
    475501            bp_the_activity();
    476502
    477             if ( $last_activity_id < bp_get_activity_id() ) {
    478                 $last_activity_id = bp_get_activity_id();
     503            $atime = strtotime( bp_get_activity_date_recorded() );
     504            if ( $last_activity_recorded < $atime ) {
     505                $last_activity_recorded = $atime;
    479506            }
    480507
     
    483510    }
    484511
    485     $newest_activities['activities'] = ob_get_contents();
    486     $newest_activities['last_id']    = $last_activity_id;
     512    $newest_activities['activities']    = ob_get_contents();
     513    $newest_activities['last_recorded'] = $last_activity_recorded;
    487514    ob_end_clean();
    488515
     
    490517    remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
    491518
    492     if ( ! empty( $newest_activities['last_id'] ) ) {
     519    if ( ! empty( $newest_activities['last_recorded'] ) ) {
    493520        $response['bp_activity_newest_activities'] = $newest_activities;
    494521    }
  • trunk/bp-activity/bp-activity-template.php

    r8201 r8251  
    548548        'secondary_id'      => false,        // secondary object ID to filter on e.g. a post_id
    549549        'offset'            => false,        // return only items >= this ID
     550        'since'             => false,        // return only items recorded since this Y-m-d H:i:s date
    550551
    551552        'meta_query'        => false,        // filter on activity meta. See WP_Meta_Query for format
     
    642643    if ( isset( $_GET['afilter'] ) && apply_filters( 'bp_activity_enable_afilter_support', false ) )
    643644        $filter = array( 'object' => $_GET['afilter'] );
    644     else if ( ! empty( $user_id ) || ! empty( $object ) || ! empty( $action ) || ! empty( $primary_id ) || ! empty( $secondary_id ) || ! empty( $offset ) )
    645         $filter = array( 'user_id' => $user_id, 'object' => $object, 'action' => $action, 'primary_id' => $primary_id, 'secondary_id' => $secondary_id, 'offset' => $offset );
     645    else if ( ! empty( $user_id ) || ! empty( $object ) || ! empty( $action ) || ! empty( $primary_id ) || ! empty( $secondary_id ) || ! empty( $offset ) || ! empty( $since ) )
     646        $filter = array( 'user_id' => $user_id, 'object' => $object, 'action' => $action, 'primary_id' => $primary_id, 'secondary_id' => $secondary_id, 'offset' => $offset, 'since' => $since );
    646647    else
    647648        $filter = false;
     
    28062807function bp_activity_recurse_comments_activity_ids( $activity = array(), $activity_ids = array() ) {
    28072808    if ( is_array( $activity ) && ! empty( $activity['activities'] ) ) {
    2808         $activity = $activity['activities'][0]; 
     2809        $activity = $activity['activities'][0];
    28092810    }
    28102811
  • trunk/bp-templates/bp-legacy/buddypress-functions.php

    r8201 r8251  
    707707        exit( '-1<div id="message" class="error"><p>' . __( 'There was a problem posting your update, please try again.', 'buddypress' ) . '</p></div>' );
    708708
    709     $last_id = isset( $_POST['offset'] ) ? absint( $_POST['offset'] ) + 1 : 0;
    710     if ( $last_id ) {
    711         $activity_args = array( 'offset' => $last_id );
    712         $bp->activity->new_update_id = $activity_id;
     709    $last_recorded = isset( $_POST['since'] ) ? date( 'Y-m-d H:i:s', intval( $_POST['since'] ) ) : 0;
     710    if ( $last_recorded ) {
     711        $activity_args = array( 'since' => $last_recorded );
     712        $bp->activity->last_recorded = $last_recorded;
    713713        add_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
    714714    } else {
     
    723723    }
    724724
    725     if ( ! empty( $last_id ) ) {
     725    if ( ! empty( $last_recorded ) ) {
    726726        remove_filter( 'bp_get_activity_css_class', 'bp_activity_newest_class', 10, 1 );
    727727    }
  • trunk/bp-templates/bp-legacy/js/buddypress.js

    r8151 r8251  
    77// Global variables to temporarly store newest activities
    88var newest_activities = '';
    9 var activity_last_id  = 0;
     9var activity_last_recorded  = 0;
    1010
    1111jq(document).ready( function() {
     
    9292    /* New posts */
    9393    jq("#aw-whats-new-submit").on( 'click', function() {
    94         var last_displayed_id = 0;
     94        var last_date_recorded = 0;
    9595        var button = jq(this);
    9696        var form = button.closest("form#whats-new-form");
     
    112112        var content = jq("#whats-new").val();
    113113        var firstrow = jq( '#buddypress ul.activity-list li' ).first();
    114 
    115         if ( firstrow.hasClass( 'load-newest' ) ) {
    116             last_displayed_id = firstrow.next().prop( 'id' ) ? firstrow.next().prop( 'id' ).replace( 'activity-','' ) : 0;
    117         } else {
    118             last_displayed_id = firstrow.prop( 'id' ) ? firstrow.prop( 'id' ).replace( 'activity-','' ) : 0;
     114        var activity_row = firstrow;
     115
     116        if ( activity_row.hasClass( 'load-newest' ) ) {
     117            activity_row = firstrow.next();
     118        }
     119
     120        timestamp = activity_row.prop( 'class' ).match( /date-recorded-([0-9]+)/ );
     121       
     122        if ( timestamp ) {
     123            last_date_recorded = timestamp[1];
    119124        }
    120125
     
    131136            'object': object,
    132137            'item_id': item_id,
    133             'offset': last_displayed_id,
     138            'since': last_date_recorded,
    134139            '_bp_as_nonce': jq('#_bp_as_nonce').val() || ''
    135140        },
     
    158163                jq("#activity-stream").prepend(response);
    159164
    160                 if ( ! last_displayed_id )
     165                if ( ! last_date_recorded )
    161166                    jq("#activity-stream li:first").addClass('new-update just-posted');
    162167
     
    185190                // reset vars to get newest activities
    186191                newest_activities = '';
    187                 activity_last_id  = 0;
     192                activity_last_recorded  = 0;
    188193            }
    189194
     
    306311            var link_href = target.attr('href');
    307312            var nonce     = link_href.split('_wpnonce=');
     313            var timestamp = li.prop( 'class' ).match( /date-recorded-([0-9]+)/ );
    308314
    309315            nonce = nonce[1];
     
    326332
    327333                    // reset vars to get newest activities
    328                     if ( activity_last_id == id ) {
     334                    if ( timestamp && activity_last_recorded == timestamp[1] ) {
    329335                        newest_activities = '';
    330                         activity_last_id  = 0;
     336                        activity_last_recorded  = 0;
    331337                    }
    332338                }
     
    338344        // Spam activity stream items
    339345        if ( target.hasClass( 'spam-activity' ) ) {
    340             var li = target.parents( 'div.activity ul li' );
     346            var li        = target.parents( 'div.activity ul li' );
     347            var timestamp = li.prop( 'class' ).match( /date-recorded-([0-9]+)/ );
    341348            target.addClass( 'loading' );
    342349
     
    355362                    li.slideUp( 300 );
    356363                    // reset vars to get newest activities
    357                     if ( activity_last_id == id ) {
     364                    if ( timestamp && activity_last_recorded == timestamp[1] ) {
    358365                        newest_activities = '';
    359                         activity_last_id  = 0;
     366                        activity_last_recorded  = 0;
    360367                    }
    361368                }
     
    408415
    409416            target.parent().hide();
     417
     418            /**
     419             * If a plugin is updating the recorded_date of an activity
     420             * it will be loaded as a new one. We need to look in the
     421             * stream and eventually remove similar ids to avoid "double".
     422             */
     423            activity_html = jq.parseHTML( newest_activities );
     424           
     425            jq.each( activity_html, function( i, el ){
     426                if( 'LI' == el.nodeName && jq(el).hasClass( 'just-posted' ) ) {
     427                    if( jq( '#' + jq(el).attr( 'id' ) ).length )
     428                        jq( '#' + jq(el).attr( 'id' ) ).remove();
     429                }
     430            } );
     431
     432            // Now the stream is cleaned, prepend newest
    410433            jq( '#buddypress ul.activity-list' ).prepend( newest_activities );
    411434
     
    14931516    // Set the last id to request after
    14941517    jq( document ).on( 'heartbeat-send.buddypress', function( e, data ) {
     1518       
     1519        firstrow = 0;
    14951520
    14961521        // First row is default latest activity id
    14971522        if ( jq( '#buddypress ul.activity-list li' ).first().prop( 'id' ) ) {
    1498             firstrow = jq( '#buddypress ul.activity-list li' ).first().prop( 'id' ).replace( 'activity-','' );
    1499         } else {
    1500             firstrow = 0;
    1501         }
    1502 
    1503         if ( 0 == activity_last_id || Number( firstrow ) > activity_last_id )
    1504             activity_last_id = Number( firstrow );
    1505 
    1506         data['bp_activity_last_id'] = activity_last_id;
    1507     });
    1508 
    1509     // Increment newest_activities and activity_last_id if data has been returned
     1523            // getting the timestamp
     1524            timestamp = jq( '#buddypress ul.activity-list li' ).first().prop( 'class' ).match( /date-recorded-([0-9]+)/ );
     1525
     1526            if ( timestamp ) {
     1527                firstrow = timestamp[1];
     1528            }
     1529        }
     1530
     1531        if ( 0 == activity_last_recorded || Number( firstrow ) > activity_last_recorded )
     1532            activity_last_recorded = Number( firstrow );
     1533
     1534        data['bp_activity_last_recorded'] = activity_last_recorded;
     1535    });
     1536
     1537    // Increment newest_activities and activity_last_recorded if data has been returned
    15101538    jq( document ).on( 'heartbeat-tick', function( e, data ) {
    15111539
     
    15161544
    15171545        newest_activities = data['bp_activity_newest_activities']['activities'] + newest_activities;
    1518         activity_last_id  = Number( data['bp_activity_newest_activities']['last_id'] );
     1546        activity_last_recorded  = Number( data['bp_activity_newest_activities']['last_recorded'] );
    15191547
    15201548        if ( jq( '#buddypress ul.activity-list li' ).first().hasClass( 'load-newest' ) )
  • trunk/tests/testcases/activity/class.BP_Activity_Activity.php

    r8249 r8251  
    283283        $this->assertEquals( array( $a3, $a2 ), $ids );
    284284    }
     285
     286    /**
     287     * @group get
     288     */
     289    public function test_get_with_since() {
     290        $now = time();
     291        $a1 = $this->factory->activity->create( array(
     292            'content' => 'Life Rules',
     293            'recorded_time' => date( 'Y-m-d H:i:s', $now - 100 ),
     294        ) );
     295        $a2 = $this->factory->activity->create( array(
     296            'content' => 'Life Drools',
     297            'recorded_time' => date( 'Y-m-d H:i:s', $now - 50 ),
     298        ) );
     299        $a3 = $this->factory->activity->create( array(
     300            'content' => 'Life Drools',
     301            'recorded_time' => date( 'Y-m-d H:i:s', $now - 10 ),
     302        ) );
     303
     304        $activity = BP_Activity_Activity::get( array(
     305            'filter' => array(
     306                'since' => date( 'Y-m-d H:i:s', $now - 70 ),
     307            ),
     308        ) );
     309        $ids = wp_list_pluck( $activity['activities'], 'id' );
     310        $this->assertEquals( array( $a3, $a2 ), $ids );
     311    }
     312
    285313    /**
    286314     * @group get_id
Note: See TracChangeset for help on using the changeset viewer.