diff --git a/Echo.php b/Echo.php index f5e87d06f..5db62d945 100644 --- a/Echo.php +++ b/Echo.php @@ -109,6 +109,9 @@ $wgJobClasses['EchoNotificationJob'] = 'EchoNotificationJob'; $wgAutoloadClasses['MWEchoNotificationEmailBundleJob'] = $dir . 'jobs/NotificationEmailBundleJob.php'; $wgJobClasses['MWEchoNotificationEmailBundleJob'] = 'MWEchoNotificationEmailBundleJob'; +// Deferred execution +$wgAutoloadClasses['EchoDeferredMarkAsReadUpdate'] = $dir . '/includes/DeferredMarkAsReadUpdate.php'; + // API $wgAutoloadClasses['ApiEchoNotifications'] = $dir . 'api/ApiEchoNotifications.php'; $wgAPIMetaModules['notifications'] = 'ApiEchoNotifications'; diff --git a/controller/NotificationController.php b/controller/NotificationController.php index 68b7393b2..3233d5c23 100644 --- a/controller/NotificationController.php +++ b/controller/NotificationController.php @@ -18,6 +18,13 @@ class EchoNotificationController { */ static protected $userWhitelist; + /** + * Queue's that failed formatting and marks them as read at end of request. + * + * @var DeferredMarkAsReadUpdate|null + */ + static protected $markAsRead; + /** * Format the notification count with Language::formatNum(). In addition, for large count, * return abbreviated version, e.g. 99+ @@ -330,12 +337,30 @@ class EchoNotificationController { restore_error_handler(); } - if ( $res ) { - return $res; - } else { - return Xml::tags( 'span', array( 'class' => 'error' ), - wfMessage( 'echo-error-no-formatter', $event->getType() )->escaped() ); + if ( $res === '' ) { + self::failFormatting( $event, $user ); } + + return $res; + } + + /** + * 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 API + if ( self::$markAsRead === null ) { + self::$markAsRead = new EchoDeferredMarkAsReadUpdate(); + DeferredUpdates::addUpdate( self::$markAsRead ); + } + self::$markAsRead->add( $event, $user ); } /** diff --git a/includes/DeferredMarkAsReadUpdate.php b/includes/DeferredMarkAsReadUpdate.php new file mode 100644 index 000000000..9b02e8cc8 --- /dev/null +++ b/includes/DeferredMarkAsReadUpdate.php @@ -0,0 +1,39 @@ +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(); + } +}