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

Change subject: Moderate notifications
......................................................................


Moderate notifications

* When a page is deleted, moderate associated
  notifications. When it is undeleted, unmoderate.

* When a notification cannot be rendered
  (canRender() returns false), moderate it.

The biggest advantage of moderation over mark-read-and-ignore
is that those notifications are filtered out at the database
level from this point on. They are not re-processed every single
time and do not affect the number of notifications returned by
the API.

Bug: T140327
Bug: T140836
Bug: T141463
Change-Id: Idefe78408fd584c13aaa9174cee3055539d92848
---
M Echo.php
M Hooks.php
M autoload.php
M includes/DataOutputFormatter.php
A includes/DeferredMarkAsDeletedUpdate.php
D includes/DeferredMarkAsReadUpdate.php
M includes/controller/NotificationController.php
M includes/mapper/EventMapper.php
M includes/mapper/NotificationMapper.php
M includes/model/Event.php
10 files changed, 151 insertions(+), 74 deletions(-)

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



diff --git a/Echo.php b/Echo.php
index c66cabb..aa13cf2 100644
--- a/Echo.php
+++ b/Echo.php
@@ -83,6 +83,9 @@
 $wgHooks['EmailUserComplete'][] = 'EchoHooks::onEmailUserComplete';
 $wgHooks['LoginFormValidErrorMessages'][] = 
'EchoHooks::onLoginFormValidErrorMessages';
 $wgHooks['OutputPageCheckLastModified'][] = 
'EchoHooks::onOutputPageCheckLastModified';
+$wgHooks['ArticleDeleteComplete'][] = 'EchoHooks::onArticleDeleteComplete';
+$wgHooks['ArticleUndelete'][] = 'EchoHooks::onArticleUndelete';
+
 
 // Extension:UserMerge support
 $wgHooks['UserMergeAccountFields'][] = 'EchoHooks::onUserMergeAccountFields';
diff --git a/Hooks.php b/Hooks.php
index f451c44..efd5fe4 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -721,12 +721,14 @@
                                        continue;
                                }
 
+                               $linkFromPageId = 
$linksUpdate->mTitle->getArticleId();
                                EchoEvent::create( array(
                                        'type' => 'page-linked',
                                        'title' => $title,
                                        'agent' => $user,
                                        'extra' => array(
-                                               'link-from-page-id' => 
$linksUpdate->mTitle->getArticleId(),
+                                               'target-page' => 
$linkFromPageId,
+                                               'link-from-page-id' => 
$linkFromPageId,
                                                'revid' => $revid,
                                        )
                                ) );
@@ -1304,4 +1306,24 @@
                return true;
        }
 
+       public static function onArticleDeleteComplete( WikiPage &$article, 
User &$user, $reason, $articleId, Content $content = null, LogEntry $logEntry ) 
{
+               \DeferredUpdates::addCallableUpdate( function () use ( 
$articleId ) {
+                       $eventMapper = new EchoEventMapper();
+                       $eventIds = $eventMapper->fetchIdsByPage( $articleId );
+                       EchoModerationController::moderate( $eventIds, true );
+               } );
+               return true;
+       }
+
+       public static function onArticleUndelete( Title $title, $create, 
$comment, $oldPageId ) {
+               if ( $create ) {
+                       \DeferredUpdates::addCallableUpdate( function () use ( 
$oldPageId ) {
+                               $eventMapper = new EchoEventMapper();
+                               $eventIds = $eventMapper->fetchIdsByPage( 
$oldPageId );
+                               EchoModerationController::moderate( $eventIds, 
false );
+                       } );
+               }
+               return true;
+       }
+
 }
diff --git a/autoload.php b/autoload.php
index 65589ed..a828fc5 100644
--- a/autoload.php
+++ b/autoload.php
@@ -30,7 +30,7 @@
        'EchoContainmentList' => __DIR__ . '/includes/ContainmentSet.php',
        'EchoContainmentSet' => __DIR__ . '/includes/ContainmentSet.php',
        'EchoDataOutputFormatter' => __DIR__ . 
'/includes/DataOutputFormatter.php',
-       'EchoDeferredMarkAsReadUpdate' => __DIR__ . 
'/includes/DeferredMarkAsReadUpdate.php',
+       'EchoDeferredMarkAsDeletedUpdate' => __DIR__ . 
'/includes/DeferredMarkAsDeletedUpdate.php',
        'EchoDiffGroup' => __DIR__ . '/includes/DiffParser.php',
        'EchoDiffParser' => __DIR__ . '/includes/DiffParser.php',
        'EchoDiffParserTest' => __DIR__ . '/tests/phpunit/DiffParserTest.php',
diff --git a/includes/DataOutputFormatter.php b/includes/DataOutputFormatter.php
index 61c7c2f..d7b866e 100644
--- a/includes/DataOutputFormatter.php
+++ b/includes/DataOutputFormatter.php
@@ -136,7 +136,7 @@
                        $formatted = self::formatNotification( $event, $user, 
$format, $lang );
                        if ( $formatted === false ) {
                                // Can't display it, so mark it as read
-                               EchoDeferredMarkAsReadUpdate::add( $event, 
$user );
+                               EchoDeferredMarkAsDeletedUpdate::add( $event );
                                return false;
                        }
                        $output['*'] = $formatted;
diff --git a/includes/DeferredMarkAsDeletedUpdate.php 
b/includes/DeferredMarkAsDeletedUpdate.php
new file mode 100644
index 0000000..0531e89
--- /dev/null
+++ b/includes/DeferredMarkAsDeletedUpdate.php
@@ -0,0 +1,72 @@
+<?php
+use MediaWiki\Logger\LoggerFactory;
+
+/**
+ * Mark event notifications as deleted at the end of a request.  Used to queue 
up
+ * individual events to mark due to formatting failures.
+ */
+class EchoDeferredMarkAsDeletedUpdate implements DeferrableUpdate {
+       /**
+        * @var array
+        */
+       protected $events = array();
+
+       /**
+        * @param EchoEvent $event
+        */
+       public static function add( EchoEvent $event ) {
+               static $update;
+               if ( $update === null ) {
+                       $update = new self();
+                       DeferredUpdates::addUpdate( $update );
+               }
+               $update->addInternal( $event );
+       }
+
+       /**
+        * @param EchoEvent $event
+        */
+       private function addInternal( EchoEvent $event ) {
+               $this->events[] = $event;
+       }
+
+       private function filterEventsWithTitleDbLag() {
+               return array_filter(
+                       $this->events,
+                       function ( EchoEvent $event ) {
+                               if ( !$event->getTitle() && $event->getTitle( 
true ) ) {
+                                       // It is very likely this event was 
found
+                                       // unreaderable because of slave lag.
+                                       // Do not moderate it at this time.
+                                       LoggerFactory::getInstance( 'Echo' 
)->debug(
+                                               
'EchoDeferredMarkAsDeletedUpdate: Event {eventId} was found unrenderable but 
its associated title exists on Master. Skipping.',
+                                               array(
+                                                       'eventId' => 
$event->getId(),
+                                                       'title' => 
$event->getTitle()->getPrefixedText(),
+                                               )
+                                       );
+                                       return false;
+                               }
+                               return true;
+                       }
+               );
+       }
+
+       /**
+        * Marks all queued notifications as read.
+        * Satisfies DeferrableUpdate interface
+        */
+       public function doUpdate() {
+               $events = $this->filterEventsWithTitleDbLag();
+
+               $eventIds = array_map(
+                       function ( EchoEvent $event ) {
+                               return $event->getId();
+                       },
+                       $events
+               );
+
+               EchoModerationController::moderate( $eventIds, true );
+               $this->events = array();
+       }
+}
diff --git a/includes/DeferredMarkAsReadUpdate.php 
b/includes/DeferredMarkAsReadUpdate.php
deleted file mode 100644
index decde62..0000000
--- a/includes/DeferredMarkAsReadUpdate.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * Mark event notifications as read at the end of a request.  Used to queue up
- * individual events to mark due to formatting failures or other uses.
- */
-class EchoDeferredMarkAsReadUpdate implements DeferrableUpdate {
-       /**
-        * @var array
-        */
-       protected $events = array();
-
-       /**
-        * @param EchoEvent $event
-        * @param User $user
-        */
-       public static function add( EchoEvent $event, User $user ) {
-               static $update;
-               if ( $update === null ) {
-                       $update = new self();
-                       DeferredUpdates::addUpdate( $update );
-               }
-               $update->addInternal( $event, $user );
-       }
-
-       /**
-        * @param EchoEvent $event
-        * @param User $user
-        */
-       private function addInternal( EchoEvent $event, User $user ) {
-               $uid = $user->getId();
-               if ( isset( $this->events[$uid] ) ) {
-                       $this->events[$uid]['eventIds'][] = $event->getId();
-               } else {
-                       $this->events[$uid] = array(
-                               'user' => $user,
-                               'eventIds' => array( $event->getId() ),
-                       );
-               }
-       }
-
-       /**
-        * Mark's all queue'd notifications as read.
-        * Satisfies DeferrableUpdate interface
-        */
-       public function doUpdate() {
-               foreach ( $this->events as $data ) {
-                       MWEchoNotifUser::newFromUser( $data['user'] 
)->markRead( $data['eventIds'] );
-               }
-               $this->events = array();
-       }
-}
diff --git a/includes/controller/NotificationController.php 
b/includes/controller/NotificationController.php
index 918a943..a6fb3cc 100644
--- a/includes/controller/NotificationController.php
+++ b/includes/controller/NotificationController.php
@@ -382,21 +382,6 @@
        }
 
        /**
-        * Event has failed to format for the given user.  Mark it as read so
-        * we do not continue to notify them about this broken event.
-        *
-        * @param EchoEvent $event
-        * @param User $user
-        */
-       protected static function failFormatting( EchoEvent $event, $user ) {
-               // FIXME: The only issue is that the badge count won't be up to 
date
-               // till you refresh the page.  Probably we could do this in the 
browser
-               // so that if the formatting is empty and the notif is unread, 
put it
-               // in the auto-mark-read APIs
-               EchoDeferredMarkAsReadUpdate::add( $event, $user );
-       }
-
-       /**
         * INTERNAL.  Must be public to be callable by the php error handling 
methods.
         *
         * Converts E_RECOVERABLE_ERROR, such as passing null to a method 
expecting
diff --git a/includes/mapper/EventMapper.php b/includes/mapper/EventMapper.php
index 8a27e5f..c231795 100644
--- a/includes/mapper/EventMapper.php
+++ b/includes/mapper/EventMapper.php
@@ -175,6 +175,52 @@
        }
 
        /**
+        * Fetch events associated with a page
+        *
+        * @param int $pageId
+        * @return EchoEvent[] Events
+        */
+       public function fetchByPage( $pageId ) {
+               $events = array();
+
+               $dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
+               $res = $dbr->select(
+                       array( 'echo_event', 'echo_target_page' ),
+                       array( 'echo_event.*' ),
+                       array(
+                               'etp_page' => $pageId
+                       ),
+                       __METHOD__,
+                       array( 'GROUP BY' => 'etp_event' ),
+                       array( 'echo_target_page' => array( 'JOIN', 
'event_id=etp_event' ) )
+               );
+               if ( $res ) {
+                       foreach ( $res as $row ) {
+                               $events[] = EchoEvent::newFromRow( $row );
+                       }
+               }
+
+               return $events;
+       }
+
+       /**
+        * Fetch event IDs associated with a page
+        *
+        * @param int $pageId
+        * @return int[] Event IDs
+        */
+       public function fetchIdsByPage( $pageId ) {
+               $events = $this->fetchByPage( $pageId );
+               $eventIds = array_map(
+                       function ( EchoEvent $event ) {
+                               return $event->getId();
+                       },
+                       $events
+               );
+               return $eventIds;
+       }
+
+       /**
         * Fetch events unread by a user and associated with a page
         *
         * @param User $user
diff --git a/includes/mapper/NotificationMapper.php 
b/includes/mapper/NotificationMapper.php
index e128456..6cc3064 100644
--- a/includes/mapper/NotificationMapper.php
+++ b/includes/mapper/NotificationMapper.php
@@ -392,7 +392,7 @@
 
                $res = $dbr->select(
                        array( 'echo_notification' ),
-                       array( 'userId' => 'notification_user' ),
+                       array( 'userId' => 'DISTINCT notification_user' ),
                        array(
                                'notification_event' => $eventIds
                        ),
diff --git a/includes/model/Event.php b/includes/model/Event.php
index 325d8ad..8641d70 100644
--- a/includes/model/Event.php
+++ b/includes/model/Event.php
@@ -465,9 +465,10 @@
        }
 
        /**
-        * @return Title|null
+        * @param bool $fromMaster
+        * @return null|Title
         */
-       public function getTitle() {
+       public function getTitle( $fromMaster = false ) {
                if ( $this->title ) {
                        return $this->title;
                } elseif ( $this->pageId ) {
@@ -477,7 +478,7 @@
                                return $this->title = $title;
                        }
 
-                       return $this->title = Title::newFromID( $this->pageId );
+                       return $this->title = Title::newFromID( $this->pageId, 
$fromMaster ? Title::GAID_FOR_UPDATE : 0 );
                } elseif ( isset( $this->extra['page_title'], 
$this->extra['page_namespace'] ) ) {
                        return $this->title = Title::makeTitleSafe(
                                $this->extra['page_namespace'],

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Idefe78408fd584c13aaa9174cee3055539d92848
Gerrit-PatchSet: 9
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: Sbisson <sbis...@wikimedia.org>
Gerrit-Reviewer: Catrope <roan.katt...@gmail.com>
Gerrit-Reviewer: Sbisson <sbis...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to