Matthias Mullie has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/258162

Change subject: Add filter to ApiEchoNotifications
......................................................................

Add filter to ApiEchoNotifications

It lets you query for read/unread/all notifications.

Bug: T119890
Change-Id: I5d09b5ff9474c77577734e9ceb0bcbcad6c99c0c
---
M includes/api/ApiEchoNotifications.php
M includes/mapper/NotificationMapper.php
2 files changed, 101 insertions(+), 53 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Echo 
refs/changes/62/258162/1

diff --git a/includes/api/ApiEchoNotifications.php 
b/includes/api/ApiEchoNotifications.php
index ba539fe..08c11fe 100644
--- a/includes/api/ApiEchoNotifications.php
+++ b/includes/api/ApiEchoNotifications.php
@@ -24,7 +24,7 @@
                        if ( $params['groupbysection'] ) {
                                foreach ( $params['sections'] as $section ) {
                                        $result[$section] = 
$this->getSectionPropList(
-                                               $user, $section, 
$params['limit'],
+                                               $user, $section, 
$params['filter'], $params['limit'],
                                                $params[$section . 'continue'], 
$params['format'], $params[$section . 'unreadfirst']
                                        );
                                        $this->getResult()->setIndexedTagName( 
$result[$section]['list'], 'notification' );
@@ -39,7 +39,7 @@
                                $result = $this->getPropList(
                                        $user,
                                        
$attributeManager->getUserEnabledEventsbySections( $user, 'web', 
$params['sections'] ),
-                                       $params['limit'], $params['continue'], 
$params['format']
+                                       $params['filter'], $params['limit'], 
$params['continue'], $params['format']
                                );
                                $this->getResult()->setIndexedTagName( 
$result['list'], 'notification' );
                                // 'index' is built on top of 'list'
@@ -65,13 +65,14 @@
         * Internal method for getting the property 'list' data for individual 
section
         * @param User $user
         * @param string $section 'alert' or 'message'
+        * @param string $filter 'all', 'read' or 'unread'
         * @param int $limit
         * @param string $continue
         * @param string $format
         * @param boolean $unreadFirst
         * @return array
         */
-       protected function getSectionPropList( User $user, $section, $limit, 
$continue, $format, $unreadFirst = false ) {
+       protected function getSectionPropList( User $user, $section, $filter, 
$limit, $continue, $format, $unreadFirst = false ) {
                $attributeManager = EchoAttributeManager::newFromGlobalVars();
                $sectionEvents = 
$attributeManager->getUserEnabledEventsbySections( $user, 'web', array( 
$section ) );
 
@@ -82,7 +83,7 @@
                        );
                } else {
                        $result = $this->getPropList(
-                               $user, $sectionEvents, $limit, $continue, 
$format, $unreadFirst
+                               $user, $sectionEvents, $filter, $limit, 
$continue, $format, $unreadFirst
                        );
                }
 
@@ -95,13 +96,14 @@
         * of a set of sections or a single section
         * @param User $user
         * @param string[] $eventTypes
+        * @param string $filter 'all', 'read' or 'unread'
         * @param int $limit
         * @param string $continue
         * @param string $format
         * @param boolean $unreadFirst
         * @return array
         */
-       protected function getPropList( User $user, array $eventTypes, $limit, 
$continue, $format, $unreadFirst = false ) {
+       protected function getPropList( User $user, array $eventTypes, $filter, 
$limit, $continue, $format, $unreadFirst = false ) {
                $result = array(
                        'list' => array(),
                        'continue' => null
@@ -109,57 +111,78 @@
 
                $notifMapper = new EchoNotificationMapper();
 
-               // Prefer unread notifications. We don't care about next offset 
in this case
-               if ( $unreadFirst ) {
-                       // query for unread notifications past 'continue' 
(offset)
-                       $notifs = $notifMapper->fetchUnreadByUser( $user, 
$limit + 1, $continue, $eventTypes );
+               switch ( $filter ) {
+                       case 'unread':
+                               $notifs = $notifMapper->fetchUnreadByUser( 
$user, $limit + 1, $continue, $eventTypes );
+                               break;
+                       case 'read':
+                               $notifs = $notifMapper->fetchReadByUser( $user, 
$limit + 1, $continue, $eventTypes );
+                               break;
+                       case 'all':
 
-                       /*
-                        * '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();
+                               // Prefer unread notifications. We don't care 
about next offset in this case
+                               if ( $unreadFirst ) {
+                                       // 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's no continue, first load 
unread notifications
+                                        * * if there's a continue, fetch 
unread notifications first
+                                        * * if there are no unread ones, 
continue must've been
+                                        *   about read notifications: fetch 'em
+                                        * * if there are unread ones but first 
one doesn't match
+                                        *   continue id, it must've been about 
read notifications:
+                                        *   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 );
+                                       // 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 + 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 )
+                                               );
+                                               foreach ( $mixedNotifs as 
$notif ) {
+                                                       
$notifs[$notif->getEvent()->getId()] = $notif;
+                                               }
+                                       }
+                               } else {
+                                       $notifs = $notifMapper->fetchByUser( 
$user, $limit + 1, $continue, $eventTypes );
                                }
-                       }
-
-                       // If there are less unread notifications than we 
requested,
-                       // then fill the result with some read notifications
-                       $count = count( $notifs );
-                       // 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 + 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 )
+                               break;
+                       default:
+                               $params = $this->getAllowedParams();
+                               $allowed = 
$params['filter'][ApiBase::PARAM_TYPE];
+                               throw new MWException(
+                                       'Unknown filter "' . $filter . '. Must 
be ' .
+                                       'one of: ' . implode( ', ', $allowed )
                                );
-                               foreach ( $mixedNotifs as $notif ) {
-                                       $notifs[$notif->getEvent()->getId()] = 
$notif;
-                               }
-                       }
-               } else {
-                       $notifs = $notifMapper->fetchByUser( $user, $limit + 1, 
$continue, $eventTypes );
+                               break;
                }
 
                foreach ( $notifs as $notif ) {
@@ -224,6 +247,14 @@
        public function getAllowedParams() {
                $sections = EchoAttributeManager::$sections;
                $params = array(
+                       'filter' => array(
+                               ApiBase::PARAM_DFLT => 'all',
+                               ApiBase::PARAM_TYPE => array(
+                                       'all',
+                                       'read',
+                                       'unread',
+                               ),
+                       ),
                        'prop' => array(
                                ApiBase::PARAM_ISMULTI => true,
                                ApiBase::PARAM_TYPE => array(
diff --git a/includes/mapper/NotificationMapper.php 
b/includes/mapper/NotificationMapper.php
index 2d5dd7e..2fde3ae 100644
--- a/includes/mapper/NotificationMapper.php
+++ b/includes/mapper/NotificationMapper.php
@@ -105,6 +105,23 @@
        }
 
        /**
+        * Get read notifications by user in the amount specified by limit 
order by
+        * notification timestamp in descending order.  We have an index to 
retrieve
+        * unread notifications but it's not optimized for ordering by 
timestamp.  The
+        * descending order is only allowed if we keep the notification in low 
volume,
+        * 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 fetchReadByUser( User $user, $limit, $continue, array 
$eventTypes = array(), $dbSource = DB_SLAVE ) {
+               return $this->fetchByUserInternal( $user, $limit, $continue, 
$eventTypes, array( 'notification_read_timestamp IS NOT NULL' ), $dbSource );
+       }
+
+       /**
         * Get Notification by user in batch along with limit, offset etc
         *
         * @param User $user the user to get notifications for

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d09b5ff9474c77577734e9ceb0bcbcad6c99c0c
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Matthias Mullie <[email protected]>

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

Reply via email to