mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Echo
synced 2024-12-18 02:40:50 +00:00
Merge "Also support continuation requests for $unreadFirst"
This commit is contained in:
commit
95290e8a4e
|
@ -309,7 +309,7 @@ class MWEchoNotifUser {
|
||||||
$eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
|
$eventTypesToLoad = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', array( $section ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$notifications = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, $eventTypesToLoad, $dbSource );
|
$notifications = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, null, $eventTypesToLoad, $dbSource );
|
||||||
if ( $notifications ) {
|
if ( $notifications ) {
|
||||||
$notification = reset( $notifications );
|
$notification = reset( $notifications );
|
||||||
$timestamp = $notification->getTimestamp();
|
$timestamp = $notification->getTimestamp();
|
||||||
|
@ -344,7 +344,7 @@ class MWEchoNotifUser {
|
||||||
// After this 'mark read', is there any unread edit-user-talk
|
// After this 'mark read', is there any unread edit-user-talk
|
||||||
// remaining? If not, we should clear the newtalk flag.
|
// remaining? If not, we should clear the newtalk flag.
|
||||||
if ( $this->mUser->getNewtalk() ) {
|
if ( $this->mUser->getNewtalk() ) {
|
||||||
$unreadEditUserTalk = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, array( 'edit-user-talk' ), DB_MASTER );
|
$unreadEditUserTalk = $this->notifMapper->fetchUnreadByUser( $this->mUser, 1, null, array( 'edit-user-talk' ), DB_MASTER );
|
||||||
if ( count( $unreadEditUserTalk ) === 0 ) {
|
if ( count( $unreadEditUserTalk ) === 0 ) {
|
||||||
$this->mUser->setNewtalk( false );
|
$this->mUser->setNewtalk( false );
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ class MWEchoNotifUser {
|
||||||
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
$attributeManager = EchoAttributeManager::newFromGlobalVars();
|
||||||
$eventTypes = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', $sections );
|
$eventTypes = $attributeManager->getUserEnabledEventsbySections( $this->mUser, 'web', $sections );
|
||||||
|
|
||||||
$notifs = $this->notifMapper->fetchUnreadByUser( $this->mUser, $wgEchoMaxUpdateCount, $eventTypes );
|
$notifs = $this->notifMapper->fetchUnreadByUser( $this->mUser, $wgEchoMaxUpdateCount, null, $eventTypes );
|
||||||
|
|
||||||
$eventIds = array_filter(
|
$eventIds = array_filter(
|
||||||
array_map( function ( EchoNotification $notif ) {
|
array_map( function ( EchoNotification $notif ) {
|
||||||
|
|
|
@ -111,17 +111,46 @@ class ApiEchoNotifications extends ApiQueryBase {
|
||||||
|
|
||||||
// Prefer unread notifications. We don't care about next offset in this case
|
// Prefer unread notifications. We don't care about next offset in this case
|
||||||
if ( $unreadFirst ) {
|
if ( $unreadFirst ) {
|
||||||
$notifs = $notifMapper->fetchUnreadByUser( $user, $limit, $eventTypes );
|
// query for unread notifications past 'continue' (offset)
|
||||||
|
$notifs = $notifMapper->fetchUnreadByUser( $user, $limit + 1, $continue, $eventTypes );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'continue' has a timestamp & id (to start with, in case there
|
||||||
|
* would be multiple events with that same timestamp)
|
||||||
|
* Unread notifications should always load first, but may be older
|
||||||
|
* than read ones, but we can work with current 'continue' format:
|
||||||
|
* * if there is no continue, first load unread notifications
|
||||||
|
* * if there is a continue, fetch unread notifications first:
|
||||||
|
* * if there are no unread ones, continue must've been about read:
|
||||||
|
* fetch 'em
|
||||||
|
* * if there are unread ones but first one doesn't match continue
|
||||||
|
* id, it must've been about read: discard unread & fetch read
|
||||||
|
*/
|
||||||
|
if ( $notifs && $continue ) {
|
||||||
|
/** @var EchoNotification $first */
|
||||||
|
$first = reset( $notifs );
|
||||||
|
$continueId = intval( trim( strrchr( $continue, '|' ), '|' ) );
|
||||||
|
if ( $first->getEvent()->getID() !== $continueId ) {
|
||||||
|
// notification doesn't match continue id, it must've been
|
||||||
|
// about read notifications: discard all unread ones
|
||||||
|
$notifs = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there are less unread notifications than we requested,
|
// If there are less unread notifications than we requested,
|
||||||
// then fill the result with some read notifications
|
// then fill the result with some read notifications
|
||||||
$count = count( $notifs );
|
$count = count( $notifs );
|
||||||
if ( $count < $limit ) {
|
// we need 1 more than $limit, so we can respond 'continue'
|
||||||
|
if ( $count <= $limit ) {
|
||||||
// Query planner should be smart enough that passing a short list of ids to exclude
|
// Query planner should be smart enough that passing a short list of ids to exclude
|
||||||
// will only visit at most that number of extra rows.
|
// will only visit at most that number of extra rows.
|
||||||
$mixedNotifs = $notifMapper->fetchByUser(
|
$mixedNotifs = $notifMapper->fetchByUser(
|
||||||
$user,
|
$user,
|
||||||
$limit - $count,
|
$limit - $count + 1,
|
||||||
null,
|
// if there were unread notifications, 'continue' was for
|
||||||
|
// unread notifications and we should start fetching read
|
||||||
|
// notifications from start
|
||||||
|
$count > 0 ? null : $continue,
|
||||||
$eventTypes,
|
$eventTypes,
|
||||||
array_keys( $notifs )
|
array_keys( $notifs )
|
||||||
);
|
);
|
||||||
|
@ -141,12 +170,10 @@ class ApiEchoNotifications extends ApiQueryBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate offset if necessary
|
// Generate offset if necessary
|
||||||
if ( !$unreadFirst ) {
|
|
||||||
if ( count( $result['list'] ) > $limit ) {
|
if ( count( $result['list'] ) > $limit ) {
|
||||||
$lastItem = array_pop( $result['list'] );
|
$lastItem = array_pop( $result['list'] );
|
||||||
$result['continue'] = $lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
|
$result['continue'] = $lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
use EchoLinkNormalizer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A formatter for the notification flyout popup
|
* A formatter for the notification flyout popup
|
||||||
|
|
|
@ -95,12 +95,13 @@ class EchoNotificationMapper extends EchoAbstractMapper {
|
||||||
* which is done via a deleteJob
|
* which is done via a deleteJob
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @param int $limit
|
* @param int $limit
|
||||||
|
* @param string $continue Used for offset
|
||||||
* @param string[] $eventTypes
|
* @param string[] $eventTypes
|
||||||
* @param int $dbSource Use master or slave database
|
* @param int $dbSource Use master or slave database
|
||||||
* @return EchoNotification[]
|
* @return EchoNotification[]
|
||||||
*/
|
*/
|
||||||
public function fetchUnreadByUser( User $user, $limit, array $eventTypes = array(), $dbSource = DB_SLAVE ) {
|
public function fetchUnreadByUser( User $user, $limit, $continue, array $eventTypes = array(), $dbSource = DB_SLAVE ) {
|
||||||
return $this->fetchByUserInternal( $user, $limit, $eventTypes, array( 'notification_read_timestamp' => null ), $dbSource );
|
return $this->fetchByUserInternal( $user, $limit, $continue, $eventTypes, array( 'notification_read_timestamp' => null ), $dbSource );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,27 +122,19 @@ class EchoNotificationMapper extends EchoAbstractMapper {
|
||||||
$conds[] = 'event_id NOT IN ( ' . $dbr->makeList( $excludeEventIds ) . ' ) ';
|
$conds[] = 'event_id NOT IN ( ' . $dbr->makeList( $excludeEventIds ) . ' ) ';
|
||||||
}
|
}
|
||||||
|
|
||||||
$offset = $this->extractQueryOffset( $continue );
|
return $this->fetchByUserInternal( $user, $limit, $continue, $eventTypes, $conds );
|
||||||
|
|
||||||
// Start points are specified
|
|
||||||
if ( $offset['timestamp'] && $offset['offset'] ) {
|
|
||||||
$ts = $dbr->addQuotes( $dbr->timestamp( $offset['timestamp'] ) );
|
|
||||||
// The offset and timestamp are those of the first notification we want to return
|
|
||||||
$conds[] = "notification_timestamp < $ts OR ( notification_timestamp = $ts AND notification_event <= " . $offset['offset'] . " )";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->fetchByUserInternal( $user, $limit, $eventTypes, $conds );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $user the user to get notifications for
|
* @param User $user the user to get notifications for
|
||||||
* @param int $limit The maximum number of notifications to return
|
* @param int $limit The maximum number of notifications to return
|
||||||
|
* @param string $continue Used for offset
|
||||||
* @param array $eventTypes Event types to load
|
* @param array $eventTypes Event types to load
|
||||||
* @param array $conds Additional query conditions.
|
* @param array $conds Additional query conditions.
|
||||||
* @param int $dbSource Use master or slave database
|
* @param int $dbSource Use master or slave database
|
||||||
* @return EchoNotification[]
|
* @return EchoNotification[]
|
||||||
*/
|
*/
|
||||||
protected function fetchByUserInternal( User $user, $limit, array $eventTypes = array(), array $conds = array(), $dbSource = DB_SLAVE ) {
|
protected function fetchByUserInternal( User $user, $limit, $continue, array $eventTypes = array(), array $conds = array(), $dbSource = DB_SLAVE ) {
|
||||||
$dbr = $this->dbFactory->getEchoDb( $dbSource );
|
$dbr = $this->dbFactory->getEchoDb( $dbSource );
|
||||||
|
|
||||||
if ( !$eventTypes ) {
|
if ( !$eventTypes ) {
|
||||||
|
@ -161,6 +154,15 @@ class EchoNotificationMapper extends EchoAbstractMapper {
|
||||||
'notification_bundle_base' => 1
|
'notification_bundle_base' => 1
|
||||||
) + $conds;
|
) + $conds;
|
||||||
|
|
||||||
|
$offset = $this->extractQueryOffset( $continue );
|
||||||
|
|
||||||
|
// Start points are specified
|
||||||
|
if ( $offset['timestamp'] && $offset['offset'] ) {
|
||||||
|
$ts = $dbr->addQuotes( $dbr->timestamp( $offset['timestamp'] ) );
|
||||||
|
// The offset and timestamp are those of the first notification we want to return
|
||||||
|
$conds[] = "notification_timestamp < $ts OR ( notification_timestamp = $ts AND notification_event <= " . $offset['offset'] . " )";
|
||||||
|
}
|
||||||
|
|
||||||
$res = $dbr->select(
|
$res = $dbr->select(
|
||||||
array( 'echo_notification', 'echo_event', 'echo_target_page' ),
|
array( 'echo_notification', 'echo_event', 'echo_target_page' ),
|
||||||
'*',
|
'*',
|
||||||
|
|
|
@ -12,7 +12,7 @@ class EchoNotificationMapperTest extends MediaWikiTestCase {
|
||||||
public function fetchUnreadByUser( User $user, $limit, array $eventTypes = array() ) {
|
public function fetchUnreadByUser( User $user, $limit, array $eventTypes = array() ) {
|
||||||
// Unsuccessful select
|
// Unsuccessful select
|
||||||
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => false ) ) );
|
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => false ) ) );
|
||||||
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '' );
|
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, null, '' );
|
||||||
$this->assertEmpty( $res );
|
$this->assertEmpty( $res );
|
||||||
|
|
||||||
// Successful select
|
// Successful select
|
||||||
|
@ -34,11 +34,11 @@ class EchoNotificationMapperTest extends MediaWikiTestCase {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => $dbResult ) ) );
|
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => $dbResult ) ) );
|
||||||
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '', array() );
|
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, null, '', array() );
|
||||||
$this->assertEmpty( $res );
|
$this->assertEmpty( $res );
|
||||||
|
|
||||||
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => $dbResult ) ) );
|
$notifMapper = new EchoNotificationMapper( $this->mockMWEchoDbFactory( array( 'select' => $dbResult ) ) );
|
||||||
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, '', array( 'test_event' ) );
|
$res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, null, '', array( 'test_event' ) );
|
||||||
$this->assertTrue( is_array( $res ) );
|
$this->assertTrue( is_array( $res ) );
|
||||||
$this->assertGreaterThan( 0, count( $res ) );
|
$this->assertGreaterThan( 0, count( $res ) );
|
||||||
foreach ( $res as $row ) {
|
foreach ( $res as $row ) {
|
||||||
|
|
Loading…
Reference in a new issue