jenkins-bot has submitted this change and it was merged.

Change subject: Also support continuation requests for $unreadFirst
......................................................................


Also support continuation requests for $unreadFirst

Right now, it'll only respond a certain, fixed, amount,
not allowing you to paginate the list.

Note: haven't properly tested all possible cases yet!

Change-Id: I84761b13a1b9203cb8e3fcc80941d739cd28659f
---
M includes/NotifUser.php
M includes/api/ApiEchoNotifications.php
M includes/formatters/EchoFlyoutFormatter.php
M includes/mapper/NotificationMapper.php
M tests/phpunit/mapper/NotificationMapperTest.php
5 files changed, 57 insertions(+), 29 deletions(-)

Approvals:
  Legoktm: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/includes/NotifUser.php b/includes/NotifUser.php
index 4f5dcac..a6927e7 100644
--- a/includes/NotifUser.php
+++ b/includes/NotifUser.php
@@ -309,7 +309,7 @@
                        $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 ) {
                        $notification = reset( $notifications );
                        $timestamp = $notification->getTimestamp();
@@ -344,7 +344,7 @@
                        // After this 'mark read', is there any unread 
edit-user-talk
                        // remaining?  If not, we should clear the newtalk flag.
                        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 ) {
                                        $this->mUser->setNewtalk( false );
                                }
@@ -379,7 +379,7 @@
                $attributeManager = EchoAttributeManager::newFromGlobalVars();
                $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(
                        array_map( function ( EchoNotification $notif ) {
diff --git a/includes/api/ApiEchoNotifications.php 
b/includes/api/ApiEchoNotifications.php
index 7e41579..ba539fe 100644
--- a/includes/api/ApiEchoNotifications.php
+++ b/includes/api/ApiEchoNotifications.php
@@ -111,17 +111,46 @@
 
                // Prefer unread notifications. We don't care about next offset 
in this case
                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,
                        // then fill the result with some read notifications
                        $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
                                // will only visit at most that number of extra 
rows.
                                $mixedNotifs = $notifMapper->fetchByUser(
                                        $user,
-                                       $limit - $count,
-                                       null,
+                                       $limit - $count + 1,
+                                       // if there were unread notifications, 
'continue' was for
+                                       // unread notifications and we should 
start fetching read
+                                       // notifications from start
+                                       $count > 0 ? null : $continue,
                                        $eventTypes,
                                        array_keys( $notifs )
                                );
@@ -141,11 +170,9 @@
                }
 
                // Generate offset if necessary
-               if ( !$unreadFirst ) {
-                       if ( count( $result['list'] ) > $limit ) {
-                               $lastItem = array_pop( $result['list'] );
-                               $result['continue'] = 
$lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
-                       }
+               if ( count( $result['list'] ) > $limit ) {
+                       $lastItem = array_pop( $result['list'] );
+                       $result['continue'] = $lastItem['timestamp']['utcunix'] 
. '|' . $lastItem['id'];
                }
 
                return $result;
diff --git a/includes/formatters/EchoFlyoutFormatter.php 
b/includes/formatters/EchoFlyoutFormatter.php
index 4f7e378..3fedd64 100644
--- a/includes/formatters/EchoFlyoutFormatter.php
+++ b/includes/formatters/EchoFlyoutFormatter.php
@@ -1,5 +1,4 @@
 <?php
-use EchoLinkNormalizer;
 
 /**
  * A formatter for the notification flyout popup
diff --git a/includes/mapper/NotificationMapper.php 
b/includes/mapper/NotificationMapper.php
index e3915af..93a41f0 100644
--- a/includes/mapper/NotificationMapper.php
+++ b/includes/mapper/NotificationMapper.php
@@ -95,12 +95,13 @@
         * which is done via a deleteJob
         * @param User $user
         * @param int $limit
+        * @param string $continue Used for offset
         * @param string[] $eventTypes
         * @param int $dbSource Use master or slave database
         * @return EchoNotification[]
         */
-       public function fetchUnreadByUser( User $user, $limit, array 
$eventTypes = array(), $dbSource = DB_SLAVE ) {
-               return $this->fetchByUserInternal( $user, $limit, $eventTypes, 
array( 'notification_read_timestamp' => null ), $dbSource );
+       public function fetchUnreadByUser( User $user, $limit, $continue, array 
$eventTypes = array(), $dbSource = DB_SLAVE ) {
+               return $this->fetchByUserInternal( $user, $limit, $continue, 
$eventTypes, array( 'notification_read_timestamp' => null ), $dbSource );
        }
 
        /**
@@ -121,27 +122,19 @@
                        $conds[] = 'event_id NOT IN ( ' . $dbr->makeList( 
$excludeEventIds ) . ' ) ';
                }
 
-               $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'] . 
" )";
-               }
-
-               return $this->fetchByUserInternal( $user, $limit, $eventTypes, 
$conds );
+               return $this->fetchByUserInternal( $user, $limit, $continue, 
$eventTypes, $conds );
        }
 
        /**
         * @param User $user the user to get notifications for
         * @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 $conds Additional query conditions.
         * @param int $dbSource Use master or slave database
         * @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 );
 
                if ( !$eventTypes ) {
@@ -161,6 +154,15 @@
                        'notification_bundle_base' => 1
                ) + $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(
                        array( 'echo_notification', 'echo_event', 
'echo_target_page' ),
                        '*',
diff --git a/tests/phpunit/mapper/NotificationMapperTest.php 
b/tests/phpunit/mapper/NotificationMapperTest.php
index 03fc008..40277d8 100644
--- a/tests/phpunit/mapper/NotificationMapperTest.php
+++ b/tests/phpunit/mapper/NotificationMapperTest.php
@@ -12,7 +12,7 @@
        public function fetchUnreadByUser( User $user, $limit, array 
$eventTypes = array() ) {
                // Unsuccessful select
                $notifMapper = new EchoNotificationMapper( 
$this->mockMWEchoDbFactory( array( 'select' => false ) ) );
-               $res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, 
'' );
+               $res = $notifMapper->fetchUnreadByUser( $this->mockUser(), 10, 
null, '' );
                $this->assertEmpty( $res );
 
                // Successful select
@@ -34,11 +34,11 @@
                        )
                );
                $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 );
 
                $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->assertGreaterThan( 0, count( $res ) );
                foreach ( $res as $row ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/257962
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I84761b13a1b9203cb8e3fcc80941d739cd28659f
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Matthias Mullie <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to