EBernhardson has uploaded a new change for review.
https://gerrit.wikimedia.org/r/150697
Change subject: Introduce AttributeManager class
......................................................................
Introduce AttributeManager class
This is a precursor to splitting notifications into
alert and message sections.
Change-Id: Ic685f7026ab9b41407b51317780bbfadd05bf9f1
---
M Echo.php
M Hooks.php
M Notifier.php
M api/ApiEchoMarkRead.php
M api/ApiEchoNotifications.php
M controller/NotificationController.php
A includes/AttributeManager.php
M includes/NotifUser.php
M includes/gateway/UserNotificationGateway.php
M includes/mapper/NotificationMapper.php
M model/Event.php
M special/SpecialNotifications.php
M tests/EmailFormatterTest.php
A tests/includes/AttributeManagerTest.php
M tests/includes/gateway/UserNotificationGatewayTest.php
M tests/includes/mapper/NotificationMapperTest.php
16 files changed, 577 insertions(+), 187 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Echo
refs/changes/97/150697/1
diff --git a/Echo.php b/Echo.php
index 8fb2dad..32c4c01 100644
--- a/Echo.php
+++ b/Echo.php
@@ -56,6 +56,7 @@
$wgAutoloadClasses['MWEchoEmailBundler'] = $dir . 'includes/EmailBundler.php';
$wgAutoloadClasses['MWDbEchoEmailBundler'] = $dir .
'includes/DbEmailBundler.php';
$wgAutoloadClasses['MWEchoEventLogging'] = $dir . 'includes/EventLogging.php';
+$wgAutoloadClasses['EchoAttributeManager'] = $dir .
'includes/AttributeManager.php';
// Database mappers && gateways
$wgAutoloadClasses['EchoEventMapper'] = $dir .
'includes/mapper/EventMapper.php';
diff --git a/Hooks.php b/Hooks.php
index a4f703b..ae38e57 100644
--- a/Hooks.php
+++ b/Hooks.php
@@ -333,9 +333,10 @@
if ( isset( $categoryData['no-dismiss'] ) && in_array(
'all' , $categoryData['no-dismiss'] ) ) {
continue;
}
+ $attributeManager =
EchoAttributeManager::newFromGlobalVars();
// See if user is eligible to recieve this notification
(per user group restrictions)
- if (
EchoNotificationController::getCategoryEligibility( $user, $category ) ) {
- $categoriesAndPriorities[$category] =
EchoNotificationController::getCategoryPriority( $category );
+ if ( $attributeManager->getCategoryEligibility( $user,
$category ) ) {
+ $categoriesAndPriorities[$category] =
$attributeManager->getCategoryPriority( $category );
}
}
asort( $categoriesAndPriorities );
@@ -732,9 +733,11 @@
// If a user is watching his/her own talk page, do not send
talk page watchlist
// email notification if the user is receiving Echo talk page
notification
if ( $title->isTalkPage() &&
$targetUser->getTalkPage()->equals( $title ) ) {
+ $attributeManager =
EchoAttributeManager::newFromGlobalVars();
+ $events = $attributeManager->getUserEnabledEvents(
$targetUser, 'email' );
if (
!self::isEchoDisabled( $targetUser )
- && in_array( 'edit-user-talk',
EchoNotificationController::getUserEnabledEvents( $targetUser, 'email' ) )
+ && in_array( 'edit-user-talk', $events )
) {
// Do not send watchlist email notification,
the user will receive an Echo notification
return false;
diff --git a/Notifier.php b/Notifier.php
index bac18ee..d32727d 100644
--- a/Notifier.php
+++ b/Notifier.php
@@ -12,7 +12,8 @@
public static function notifyWithNotification( $user, $event ) {
// Only create the notification if the user wants to recieve
that type
// of notification and they are eligible to recieve it. See bug
47664.
- $userWebNotifications =
EchoNotificationController::getUserEnabledEvents( $user, 'web' );
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $userWebNotifications =
$attributeManager->getUserEnabledEvents( $user, 'web' );
if ( !in_array( $event->getType(), $userWebNotifications ) ) {
return;
}
@@ -40,11 +41,13 @@
return false;
}
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $userEmailNotifications =
$attributeManager->getUserEnabledEvents( $user, 'email' );
// See if the user wants to receive emails for this category or
the user is eligible to receive this email
- if ( in_array( $event->getType(),
EchoNotificationController::getUserEnabledEvents( $user, 'email' ) ) ) {
+ if ( in_array( $event->getType(), $userEmailNotifications ) ) {
global $wgEchoEnableEmailBatch, $wgEchoNotifications,
$wgNotificationSender, $wgNotificationSenderName, $wgNotificationReplyName,
$wgEchoBundleEmailInterval;
- $priority =
EchoNotificationController::getNotificationPriority( $event->getType() );
+ $priority = $attributeManager->getNotificationPriority(
$event->getType() );
$bundleString = $bundleHash = '';
diff --git a/api/ApiEchoMarkRead.php b/api/ApiEchoMarkRead.php
index 5a2a387..cc1e941 100644
--- a/api/ApiEchoMarkRead.php
+++ b/api/ApiEchoMarkRead.php
@@ -25,11 +25,9 @@
}
}
- $rawCount = $notifUser->getNotificationCount();
-
$result = array(
'result' => 'success',
- 'rawcount' => $rawCount,
+ 'rawcount' => $notifUser->getNotificationCount(),
'count' =>
EchoNotificationController::formatNotificationCount( $rawCount ),
);
$this->getResult()->addValue( 'query', $this->getModuleName(),
$result );
diff --git a/api/ApiEchoNotifications.php b/api/ApiEchoNotifications.php
index 9e85e86..dfbbce6 100644
--- a/api/ApiEchoNotifications.php
+++ b/api/ApiEchoNotifications.php
@@ -21,46 +21,191 @@
$prop = $params['prop'];
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
$result = array();
if ( in_array( 'list', $prop ) ) {
- $result['list'] = array();
- $notifMapper = new EchoNotificationMapper(
MWEchoDbFactory::newFromDefault() );
- $notifs = $notifMapper->fetchByUser( $user,
$params['limit'] + 1, $params['continue'], 'web' );
- foreach ( $notifs as $notif ) {
- $result['list'][$notif->getEvent()->getID()] =
EchoDataOutputFormatter::formatOutput( $notif, $params['format'], $user );
- }
-
- // check if there is more elements than we request
- if ( count( $result['list'] ) > $params['limit'] ) {
- $lastItem = array_pop( $result['list'] );
- $result['continue'] =
$lastItem['timestamp']['utcunix'] . '|' . $lastItem['id'];
- } else {
- $result['continue'] = null;
- }
+ $result = $this->getPropList(
+ $user,
+ $attributeManager->getUserEnabledEvents( $user,
'web' ),
+ $params['limit'], $params['continue'],
$params['format']
+ );
$this->getResult()->setIndexedTagName( $result['list'],
'notification' );
+ // 'index' is built on top of 'list'
+ if ( in_array( 'index', $prop ) ) {
+ $result['index'] = $this->getPropIndex(
$result['list'] );
+ $this->getResult()->setIndexedTagName(
$result['index'], 'id' );
+ }
}
if ( in_array( 'count', $prop ) ) {
- $rawCount = $notifUser->getNotificationCount();
- $result['rawcount'] = $rawCount;
- $result['count'] =
EchoNotificationController::formatNotificationCount( $rawCount );
- }
-
- if ( in_array( 'index', $prop ) ) {
- $result['index'] = array();
- foreach ( array_keys( $result['list'] ) as $key ) {
- // Don't include the XML tag name ('_element'
key)
- if ( $key != '_element' ) {
- $result['index'][] = $key;
- }
- }
- $this->getResult()->setIndexedTagName(
$result['index'], 'id' );
+ $result += $this->getPropCount( $user );
}
$this->getResult()->setIndexedTagName( $result, 'notification'
);
$this->getResult()->addValue( 'query', $this->getModuleName(),
$result );
}
+ /**
+ * Internal helper method for getting property 'count' data
+ */
+ protected function getPropCount( User $user ) {
+ $result = array();
+ $notifUser = MWEchoNotifUser::newFromUser( $user );
+ // Always get total count
+ $rawCount = $notifUser->getNotificationCount();
+ $result['rawcount'] = $rawCount;
+ $result['count'] =
EchoNotificationController::formatNotificationCount( $rawCount );
+ return $result;
+ }
+
+ /**
+ * Internal helper method for getting property 'list' data
+ */
+ protected function getPropList( User $user, array $eventTypesToLoad,
$limit, $continue, $format ) {
+ $result = array(
+ 'list' => array(),
+ 'continue' => null
+ );
+
+ // Fetch the result for the event types above
+ $notifMapper = new EchoNotificationMapper(
MWEchoDbFactory::newFromDefault() );
+ $notifs = $notifMapper->fetchByUser( $user, $limit + 1,
$continue, $eventTypesToLoad );
+ foreach ( $notifs as $notif ) {
+ $result['list'][$notif->getEvent()->getID()] =
EchoDataOutputFormatter::formatOutput( $notif, $format, $user );
+ }
+
+ if ( count( $result['list'] ) > $limit ) {
+ $lastItem = array_pop( $result['list'] );
+ $result['continue'] = $lastItem['timestamp']['utcunix']
. '|' . $lastItem['id'];
+ }
+
+ return $result;
+ }
+
+ /**
+ * Internal helper method for getting property 'index' data
+ */
+ protected function getPropIndex( $list ) {
+ $result = array();
+ foreach ( array_keys( $list ) as $key ) {
+ // Don't include the XML tag name ('_element' key)
+ if ( $key != '_element' ) {
+ $result[] = $key;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Get a list of notifications based on the passed parameters
+ *
+ * @param $user User the user to get notifications for
+ * @param $format string|bool false to not format any notifications,
string to a specific output format
+ * @param $limit int The maximum number of notifications to return
+ * @param $continue string Used for offset
+ *
+ * @return array
+ */
+ public static function getNotifications( $user, $format = false, $limit
= 20, $continue = null ) {
+ global $wgEchoBackend;
+
+ $output = array();
+
+ // TODO: Make 'web' based on a new API param?
+ $res = $wgEchoBackend->loadNotifications( $user, $limit,
$continue, 'web' );
+
+ foreach ( $res as $row ) {
+ $event = EchoEvent::newFromRow( $row );
+ if ( $row->notification_bundle_base &&
$row->notification_bundle_display_hash ) {
+ $event->setBundleHash(
$row->notification_bundle_display_hash );
+ }
+
+ $timestampMw = self::getUserLocalTime( $user,
$row->notification_timestamp );
+
+ // Start creating date section header
+ $now = wfTimestamp();
+ $dateFormat = substr( $timestampMw, 0, 8 );
+ if ( substr( self::getUserLocalTime( $user, $now ), 0,
8 ) === $dateFormat ) {
+ // 'Today'
+ $date = wfMessage( 'echo-date-today'
)->escaped();
+ } elseif ( substr( self::getUserLocalTime( $user, $now
- 86400 ), 0, 8 ) === $dateFormat ) {
+ // 'Yesterday'
+ $date = wfMessage( 'echo-date-yesterday'
)->escaped();
+ } else {
+ // 'May 10' or '10 May' (depending on user's
date format preference)
+ $lang =
RequestContext::getMain()->getLanguage();
+ $dateFormat = $lang->getDateFormatString(
'pretty', $user->getDatePreference() ?: 'default' );
+ $date = $lang->sprintfDate( $dateFormat,
$timestampMw );
+ }
+ // End creating date section header
+
+ $thisEvent = array(
+ 'id' => $event->getId(),
+ 'type' => $event->getType(),
+ 'category' => $event->getCategory(),
+ 'timestamp' => array(
+ // UTC timestamp in UNIX format used
for loading more notification
+ 'utcunix' => wfTimestamp( TS_UNIX,
$row->notification_timestamp ),
+ 'unix' => self::getUserLocalTime(
$user, $row->notification_timestamp, TS_UNIX ),
+ 'mw' => $timestampMw,
+ 'date' => $date
+ ),
+ );
+
+ if ( $event->getVariant() ) {
+ $thisEvent['variant'] = $event->getVariant();
+ }
+
+ if ( $event->getTitle() ) {
+ $thisEvent['title'] = array(
+ 'full' =>
$event->getTitle()->getPrefixedText(),
+ 'namespace' =>
$event->getTitle()->getNSText(),
+ 'namespace-key' =>
$event->getTitle()->getNamespace(),
+ 'text' => $event->getTitle()->getText(),
+ );
+ }
+
+ if ( $event->getAgent() ) {
+ if ( $event->userCan( Revision::DELETED_USER,
$user ) ) {
+ $thisEvent['agent'] = array(
+ 'id' =>
$event->getAgent()->getId(),
+ 'name' =>
$event->getAgent()->getName(),
+ );
+ } else {
+ $thisEvent['agent'] = array(
'userhidden' => '' );
+ }
+ }
+
+ if ( $row->notification_read_timestamp ) {
+ $thisEvent['read'] =
$row->notification_read_timestamp;
+ }
+
+ if ( $format ) {
+ $thisEvent['*'] =
EchoNotificationController::formatNotification(
+ $event, $user, $format );
+ }
+
+ $output[$event->getID()] = $thisEvent;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Internal helper function for converting UTC timezone to a user's
timezone
+ *
+ * @param $user User
+ * @param $ts string
+ * @param $format int output format
+ *
+ * @return string
+ */
+ private static function getUserLocalTime( $user, $ts, $format = TS_MW )
{
+ $timestamp = new MWTimestamp( $ts );
+ $timestamp->offsetForUser( $user );
+ return $timestamp->getTimestamp( $format );
+ }
+
public function getAllowedParams() {
return array(
'prop' => array(
diff --git a/controller/NotificationController.php
b/controller/NotificationController.php
index 638cb75..c391659 100644
--- a/controller/NotificationController.php
+++ b/controller/NotificationController.php
@@ -8,108 +8,6 @@
static protected $userWhitelist;
/**
- * Get the enabled events for a user, which excludes user-dismissed
events
- * from the general enabled events
- * @param $user User
- * @param $outputFormat string
- * @return array
- */
- public static function getUserEnabledEvents( $user, $outputFormat ) {
- global $wgEchoNotifications;
- $eventTypesToLoad = $wgEchoNotifications;
- foreach ( $eventTypesToLoad as $eventType => $eventData ) {
- $category = self::getNotificationCategory( $eventType );
- // Make sure the user is eligible to recieve this type
of notification
- if ( !self::getCategoryEligibility( $user, $category )
) {
- unset( $eventTypesToLoad[$eventType] );
- }
- if ( !$user->getOption( 'echo-subscriptions-' .
$outputFormat . '-' . $category ) ) {
- unset( $eventTypesToLoad[$eventType] );
- }
- }
- return array_keys( $eventTypesToLoad );
- }
-
- /**
- * See if a user is eligible to recieve a certain type of notification
- * (based on user groups, not user preferences)
- *
- * @param $user User object
- * @param $notificationType string A notification type defined in
$wgEchoNotifications
- * @return boolean
- */
- public static function getNotificationEligibility( $user,
$notificationType ) {
- $category = self::getNotificationCategory( $notificationType );
- return self::getCategoryEligibility( $user, $category );
- }
-
- /**
- * See if a user is eligible to recieve a certain type of notification
- * (based on user groups, not user preferences)
- *
- * @param $user User object
- * @param $category string A notification category defined in
$wgEchoNotificationCategories
- * @return boolean
- */
- public static function getCategoryEligibility( $user, $category ) {
- global $wgEchoNotificationCategories;
- $usersGroups = $user->getGroups();
- if ( isset(
$wgEchoNotificationCategories[$category]['usergroups'] ) ) {
- $allowedGroups =
$wgEchoNotificationCategories[$category]['usergroups'];
- if ( !array_intersect( $usersGroups, $allowedGroups ) )
{
- return false;
- }
- }
- return true;
- }
-
- /**
- * Get the priority for a specific notification type
- *
- * @param $notificationType string A notification type defined in
$wgEchoNotifications
- * @return integer From 1 to 10 (10 is default)
- */
- public static function getNotificationPriority( $notificationType ) {
- $category = self::getNotificationCategory( $notificationType );
- return self::getCategoryPriority( $category );
- }
-
- /**
- * Get the priority for a notification category
- *
- * @param $category string A notification category defined in
$wgEchoNotificationCategories
- * @return integer From 1 to 10 (10 is default)
- */
- public static function getCategoryPriority( $category ) {
- global $wgEchoNotificationCategories;
- if ( isset(
$wgEchoNotificationCategories[$category]['priority'] ) ) {
- $priority =
$wgEchoNotificationCategories[$category]['priority'];
- if ( $priority >= 1 && $priority <= 10 ) {
- return $priority;
- }
- }
- return 10;
- }
-
- /**
- * Get the notification category for a notification type
- *
- * @param $notificationType string A notification type defined in
$wgEchoNotifications
- * @return String The name of the notification category or 'other' if no
- * category is explicitly assigned.
- */
- public static function getNotificationCategory( $notificationType ) {
- global $wgEchoNotifications, $wgEchoNotificationCategories;
- if ( isset( $wgEchoNotifications[$notificationType]['category']
) ) {
- $category =
$wgEchoNotifications[$notificationType]['category'];
- if ( isset( $wgEchoNotificationCategories[$category] )
) {
- return $category;
- }
- }
- return 'other';
- }
-
- /**
* Format the notification count with Language::formatNum(). In
addition, for large count,
* return abbreviated version, e.g. 99+
* @param $count int
diff --git a/includes/AttributeManager.php b/includes/AttributeManager.php
new file mode 100644
index 0000000..c7b85fe
--- /dev/null
+++ b/includes/AttributeManager.php
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * An object that manages attributes of echo notifications: category,
elegibility,
+ * group, section etc.
+ */
+class EchoAttributeManager {
+
+ /**
+ * @var array
+ */
+ protected $notifications;
+
+ /**
+ * @var array
+ */
+ protected $categories;
+
+ /**
+ * An array of EchoAttributeManager instance created from global
variables
+ * @param EchoAttributeManager[]
+ */
+ protected static $globalVarInstance = array();
+
+ /**
+ * @param array notification attributes
+ * @param array notification categories
+ */
+ public function __construct( array $notifications, array $categories ) {
+ // Extensions can define their own notifications and categories
+ $this->notifications = $notifications;
+ $this->categories = $categories;
+ }
+
+ /**
+ * Create an instance from global variables
+ * @return EchoAttributeManager
+ */
+ public static function newFromGlobalVars() {
+ global $wgEchoNotifications, $wgEchoNotificationCategories;
+
+ // Unit test may alter the global data for test purpose
+ if ( defined( 'MW_PHPUNIT_TEST' ) && MW_PHPUNIT_TEST ) {
+ return new self( $wgEchoNotifications,
$wgEchoNotificationCategories );
+ }
+ // A job queue job may run against different wikis, the
singleton
+ // instance should be a per wiki singleton
+ $wikiId = wfWikiId();
+ if ( !isset( self::$globalVarInstance[$wikiId] ) ) {
+ self::$globalVarInstance[$wikiId] = new self(
+ $wgEchoNotifications,
+ $wgEchoNotificationCategories
+ );
+ }
+ return self::$globalVarInstance[$wikiId];
+ }
+
+ /**
+ * Get the enabled events for a user, which excludes user-dismissed
events
+ * from the general enabled events
+ * @param User
+ * @param string web/email
+ * @return string[]
+ */
+ public function getUserEnabledEvents( User $user, $outputFormat ) {
+ $eventTypesToLoad = $this->notifications;
+ foreach ( $eventTypesToLoad as $eventType => $eventData ) {
+ $category = $this->getNotificationCategory( $eventType
);
+ // Make sure the user is eligible to recieve this type
of notification
+ if ( !$this->getCategoryEligibility( $user, $category )
) {
+ unset( $eventTypesToLoad[$eventType] );
+ }
+ if ( !$user->getOption( 'echo-subscriptions-' .
$outputFormat . '-' . $category ) ) {
+ unset( $eventTypesToLoad[$eventType] );
+ }
+ }
+ $eventTypes = array_keys( $eventTypesToLoad );
+
+ return $eventTypes;
+ }
+
+ /**
+ * Get alert notification event. Notifications without a section
attributes
+ * default to section alert
+ * @return array
+ */
+ public function getEvents() {
+ return array_keys( $this->notifications );
+ }
+
+ /**
+ * See if a user is eligible to recieve a certain type of notification
+ * (based on user groups, not user preferences)
+ *
+ * @param User
+ * @param string A notification category defined in
$wgEchoNotificationCategories
+ * @return boolean
+ */
+ public function getCategoryEligibility( $user, $category ) {
+ $usersGroups = $user->getGroups();
+ if ( isset( $this->categories[$category]['usergroups'] ) ) {
+ $allowedGroups =
$this->categories[$category]['usergroups'];
+ if ( !array_intersect( $usersGroups, $allowedGroups ) )
{
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get the priority for a specific notification type
+ *
+ * @param string A notification type defined in $wgEchoNotifications
+ * @return integer From 1 to 10 (10 is default)
+ */
+ public function getNotificationPriority( $notificationType ) {
+ $category = $this->getNotificationCategory( $notificationType );
+ return $this->getCategoryPriority( $category );
+ }
+
+ /**
+ * Get the priority for a notification category
+ *
+ * @param string A notification category defined in
$wgEchoNotificationCategories
+ * @return integer From 1 to 10 (10 is default)
+ */
+ public function getCategoryPriority( $category ) {
+ if ( isset( $this->categories[$category]['priority'] ) ) {
+ $priority = $this->categories[$category]['priority'];
+ if ( $priority >= 1 && $priority <= 10 ) {
+ return $priority;
+ }
+ }
+ return 10;
+ }
+
+ /**
+ * Get the notification category for a notification type
+ *
+ * @param string A notification type defined in $wgEchoNotifications
+ * @return string The name of the notification category or 'other' if no
+ * category is explicitly assigned.
+ */
+ public function getNotificationCategory( $notificationType ) {
+ if ( isset( $this->notifications[$notificationType]['category']
) ) {
+ $category =
$this->notifications[$notificationType]['category'];
+ if ( isset( $this->categories[$category] ) ) {
+ return $category;
+ }
+ }
+ return 'other';
+ }
+}
diff --git a/includes/NotifUser.php b/includes/NotifUser.php
index 670ed85..4194a14 100644
--- a/includes/NotifUser.php
+++ b/includes/NotifUser.php
@@ -51,7 +51,7 @@
new EchoUserNotificationGateway( $user,
MWEchoDbFactory::newFromDefault() )
);
}
-
+
/**
* Clear talk page notification when users visit their talk pages. This
* only resets if the notification count is less than max notification
@@ -122,6 +122,7 @@
*
* @param $cached bool Set to false to bypass the cache.
* @param $dbSource int use master or slave database to pull count
+ * @param $section string
* @return integer: Number of unread notifications.
*/
public function getNotificationCount( $cached = true, $dbSource =
DB_SLAVE ) {
@@ -131,13 +132,19 @@
return 0;
}
- $memcKey = wfMemcKey( 'echo-notification-count',
$this->mUser->getId(), $wgEchoConfig['version'] );
+ $memcKey = wfMemcKey(
+ 'echo-notification-count',
+ $this->mUser->getId(),
+ $wgEchoConfig['version']
+ );
if ( $cached && $this->cache->get( $memcKey ) !== false ) {
return (int)$this->cache->get( $memcKey );
}
- $count = $this->userNotifGateway->getNotificationCount(
$dbSource );
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $eventTypesToLoad = $attributeManager->getUserEnabledEvents(
$this->mUser, 'web' );
+ $count = $this->userNotifGateway->getNotificationCount(
$dbSource, $eventTypesToLoad );
$this->cache->set( $memcKey, $count, 86400 );
diff --git a/includes/gateway/UserNotificationGateway.php
b/includes/gateway/UserNotificationGateway.php
index b138a6c..1a1ac17 100644
--- a/includes/gateway/UserNotificationGateway.php
+++ b/includes/gateway/UserNotificationGateway.php
@@ -74,16 +74,16 @@
}
/**
- * @param $dbSource string use master or slave storage to pull count
+ * Get notification count for the types specified
+ * @param int use master or slave storage to pull count
+ * @param array event types to retrieve
* @return int
*/
- public function getNotificationCount( $dbSource ) {
+ public function getNotificationCount( $dbSource, array
$eventTypesToLoad = array() ) {
// double check
if ( !in_array( $dbSource, array( DB_SLAVE, DB_MASTER ) ) ) {
$dbSource = DB_SLAVE;
}
-
- $eventTypesToLoad =
EchoNotificationController::getUserEnabledEvents( $this->user, 'web' );
if ( !$eventTypesToLoad ) {
return 0;
diff --git a/includes/mapper/NotificationMapper.php
b/includes/mapper/NotificationMapper.php
index fd1756d..cdca78d 100644
--- a/includes/mapper/NotificationMapper.php
+++ b/includes/mapper/NotificationMapper.php
@@ -91,17 +91,23 @@
* @param User the user to get notifications for
* @param int The maximum number of notifications to return
* @param string Used for offset
- * @param string Notification distribution type ( web, email, etc.)
+ * @param array Event types to load
* @return EchoNotification[]
*/
- public function fetchByUser( User $user, $limit, $continue,
$distributionType = 'web' ) {
+ public function fetchByUser( User $user, $limit, $continue, array
$eventTypesToLoad = array() ) {
$dbr = $this->dbFactory->getEchoDb( DB_SLAVE );
- $eventTypesToLoad =
EchoNotificationController::getUserEnabledEvents( $user, $distributionType );
if ( !$eventTypesToLoad ) {
return array();
}
+ // There is a problem with querying by event type, if a user
has only one or none
+ // flow notification and huge amount other notications, the
lookup of only flow
+ // notification will result in a slow query. Luckily users
won't have that many
+ // notifications. We should have some cron job to remove old
notifications so
+ // the notification volume is in a reasonable amount for such
case. The other option
+ // is to denormalize notification table with event_type and
lookup index.
+ //
// Look for notifications with base = 1
$conds = array(
'notification_user' => $user->getID(),
diff --git a/model/Event.php b/model/Event.php
index b66343f..48e7b62 100644
--- a/model/Event.php
+++ b/model/Event.php
@@ -421,7 +421,8 @@
* @return string
*/
public function getCategory() {
- return EchoNotificationController::getNotificationCategory(
$this->type );
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ return $attributeManager->getNotificationCategory( $this->type
);
}
public function setType( $type ) {
diff --git a/special/SpecialNotifications.php b/special/SpecialNotifications.php
index 4ca78bd..1f7f69f 100644
--- a/special/SpecialNotifications.php
+++ b/special/SpecialNotifications.php
@@ -20,13 +20,14 @@
$user = $this->getUser();
if ( $user->isAnon() ) {
- $notificationsPageName =
$this->getPageTitle()->getPrefixedDBkey();
- $returnTo = array( 'returnto' => $notificationsPageName
);
- $signupTitle = SpecialPage::getTitleFor( 'UserLogin',
'signup' );
- $signupURL = $signupTitle->getFullURL( $returnTo );
- $loginTitle = SpecialPage::getTitleFor( 'UserLogin' );
- $loginURL = $loginTitle->getFullURL( $returnTo );
- $anonMsgHtml = $this->msg( 'echo-anon', $signupURL,
$loginURL )->parse();
+ // return to this title upon login
+ $returnTo = array( 'returnto' =>
$this->getPageTitle()->getPrefixedDBkey() );
+ // the html message for anon users
+ $anonMsgHtml = $this->msg(
+ 'echo-anon',
+ SpecialPage::getTitleFor( 'UserLogin', 'signup'
)->getFullURL( $returnTo ),
+ SpecialPage::getTitleFor( 'UserLogin'
)->getFullURL( $returnTo )
+ )->parse();
$out->addHTML( Html::rawElement( 'span', array( 'class'
=> 'plainlinks' ), $anonMsgHtml ) );
return;
}
@@ -40,7 +41,14 @@
// Pull the notifications
$notif = array();
$notificationMapper = new EchoNotificationMapper(
MWEchoDbFactory::newFromDefault() );
- $notifications = $notificationMapper->fetchByUser( $user,
self::$displayNum + 1, $continue, 'web' );
+
+ $attributeManager = EchoAttributeManager::newFromGlobalVars();
+ $notifications = $notificationMapper->fetchByUser(
+ $user,
+ /* $limit = */self::$displayNum + 1,
+ $continue,
+ $attributeManager->getUserEnabledEvents( $user, 'web' )
+ );
foreach ( $notifications as $notification ) {
$notif[] = EchoDataOutputFormatter::formatOutput(
$notification, 'html', $user );
}
diff --git a/tests/EmailFormatterTest.php b/tests/EmailFormatterTest.php
index ef69e5b..345c8ed 100644
--- a/tests/EmailFormatterTest.php
+++ b/tests/EmailFormatterTest.php
@@ -69,6 +69,7 @@
$methods = get_class_methods( 'EchoEvent' );
$methods = array_diff( $methods, array( 'userCan',
'getLinkMessage', 'getLinkDestination' ) );
+ $attribManager = EchoAttributeManager::newFromGlobalVars();
$event = $this->getMockBuilder( 'EchoEvent' )
->disableOriginalConstructor()
->setMethods( $methods )
@@ -78,7 +79,7 @@
->will( $this->returnValue( $type ) );
$event->expects( $this->any() )
->method( 'getCategory' )
- ->will( $this->returnValue(
EchoNotificationController::getNotificationCategory( $type ) ) );
+ ->will( $this->returnValue(
$attribManager->getNotificationCategory( $type ) ) );
return $event;
}
diff --git a/tests/includes/AttributeManagerTest.php
b/tests/includes/AttributeManagerTest.php
new file mode 100644
index 0000000..dc0157d
--- /dev/null
+++ b/tests/includes/AttributeManagerTest.php
@@ -0,0 +1,175 @@
+<?php
+
+class EchoAttributeManagerTest extends MediaWikiTestCase {
+
+ public function testNewFromGlobalVars() {
+ $this->assertInstanceOf( 'EchoAttributeManager',
EchoAttributeManager::newFromGlobalVars() );
+ }
+
+ public function testGetCategoryEligibility() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertTrue( $manager->getCategoryEligibility(
$this->mockUser(), 'category_one' ) );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'sysop'
+ )
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertFalse( $manager->getCategoryEligibility(
$this->mockUser(), 'category_one' ) );
+ }
+
+ public function testGetNotificationCategory() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getNotificationCategory(
'event_one' ), 'category_one' );
+
+ $manager = new EchoAttributeManager( $notif, array() );
+ $this->assertEquals( $manager->getNotificationCategory(
'event_one' ), 'other' );
+
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_two'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10
+ )
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getNotificationCategory(
'event_one' ), 'other' );
+ }
+
+ public function testGetCategoryPriority() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_two'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ ),
+ 'category_two' => array (
+ 'priority' => 100
+ ),
+ 'category_three' => array (
+ 'priority' => -10
+ ),
+ 'category_four' => array ()
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( 6, $manager->getCategoryPriority(
'category_one' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority(
'category_two' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority(
'category_three' ) );
+ $this->assertEquals( 10, $manager->getCategoryPriority(
'category_four' ) );
+ }
+
+ public function testGetNotificationPriority() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three'
+ ),
+ 'event_four' => array (
+ 'category' => 'category_four'
+ )
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 6
+ ),
+ 'category_two' => array (
+ 'priority' => 100
+ ),
+ 'category_three' => array (
+ 'priority' => -10
+ ),
+ 'category_four' => array ()
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( 6, $manager->getNotificationPriority(
'event_one' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority(
'event_two' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority(
'event_three' ) );
+ $this->assertEquals( 10, $manager->getNotificationPriority(
'event_four' ) );
+ }
+
+ public function testGetUserEnabledEvents() {
+ $notif = array(
+ 'event_one' => array (
+ 'category' => 'category_one'
+ ),
+ 'event_two' => array (
+ 'category' => 'category_two'
+ ),
+ 'event_three' => array (
+ 'category' => 'category_three'
+ ),
+ );
+ $category = array(
+ 'category_one' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'sysop'
+ )
+ ),
+ 'category_two' => array (
+ 'priority' => 10,
+ 'usergroups' => array(
+ 'echo_group'
+ )
+ ),
+ 'category_three' => array (
+ 'priority' => 10,
+ ),
+ );
+ $manager = new EchoAttributeManager( $notif, $category );
+ $this->assertEquals( $manager->getUserEnabledEvents(
$this->mockUser(), 'web' ), array( 'event_two', 'event_three' ) );
+ }
+
+ /**
+ * Mock object of User
+ */
+ protected function mockUser() {
+ $user = $this->getMockBuilder( 'User' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $user->expects( $this->any() )
+ ->method( 'getID' )
+ ->will( $this->returnValue( 1 ) );
+ $user->expects( $this->any() )
+ ->method( 'getOption' )
+ ->will( $this->returnValue( true ) );
+ $user->expects( $this->any() )
+ ->method( 'getGroups' )
+ ->will( $this->returnValue( array( 'echo_group' ) ) );
+ return $user;
+ }
+}
diff --git a/tests/includes/gateway/UserNotificationGatewayTest.php
b/tests/includes/gateway/UserNotificationGatewayTest.php
index b4f807a..8ae94f6 100644
--- a/tests/includes/gateway/UserNotificationGatewayTest.php
+++ b/tests/includes/gateway/UserNotificationGatewayTest.php
@@ -27,35 +27,21 @@
}
public function testGetNotificationCount() {
- global $wgEchoNotificationCategories;
- $previous = $wgEchoNotificationCategories;
-
- // Alter the category group so the user is always elegible to
- // view some notification types.
- foreach ( $wgEchoNotificationCategories as &$value ) {
- $value['usergroups'] = array( 'echo_group' );
- }
- unset( $value );
-
- // successful select
+ // unsuccessful select
$gateway = new EchoUserNotificationGateway( $this->mockUser(),
$this->mockMWEchoDbFactory( array( 'select' => false ) ) );
- $this->assertEquals( 0, $gateway->getNotificationCount(
DB_SLAVE ) );
+ $this->assertEquals( 0, $gateway->getNotificationCount(
DB_SLAVE, array( 'event_one' ) ) );
+
+ // successful select of alert
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(),
$this->mockMWEchoDbFactory( array( 'select' => array( 1, 2 ) ) ) );
+ $this->assertEquals( 2, $gateway->getNotificationCount(
DB_SLAVE, array( 'event_one', 'event_two' ) ) );
+
+ // there is event, should return 0
+ $gateway = new EchoUserNotificationGateway( $this->mockUser(),
$this->mockMWEchoDbFactory( array( 'select' => array( 1, 2 ) ) ) );
+ $this->assertEquals( 0, $gateway->getNotificationCount(
DB_SLAVE, array() ) );
// successful select
$gateway = new EchoUserNotificationGateway( $this->mockUser(),
$this->mockMWEchoDbFactory( array( 'select' => array( 1, 2, 3 ) ) ) );
- $this->assertEquals( 3, $gateway->getNotificationCount(
DB_SLAVE ) );
-
- // Alter the category group so the user is not elegible to
- // view any notification types.
- foreach ( $wgEchoNotificationCategories as &$value ) {
- $value['usergroups'] = array( 'sysop' );
- }
- unset( $value );
-
- $gateway = new EchoUserNotificationGateway( $this->mockUser(),
$this->mockMWEchoDbFactory( array( 'select' => array( 1, 2, 3 ) ) ) );
- $this->assertEquals( 0, $gateway->getNotificationCount(
DB_SLAVE ) );
-
- $wgEchoNotificationCategories = $previous;
+ $this->assertEquals( 3, $gateway->getNotificationCount(
DB_SLAVE, array( 'event_one' ) ) );
}
public function testGetUnreadNotifications() {
@@ -75,7 +61,7 @@
/**
* Mock object of User
*/
- protected function mockUser() {
+ protected function mockUser( $group = 'echo_group' ) {
$user = $this->getMockBuilder( 'User' )
->disableOriginalConstructor()
->getMock();
@@ -87,7 +73,7 @@
->will( $this->returnValue( true ) );
$user->expects( $this->any() )
->method( 'getGroups' )
- ->will( $this->returnValue( array( 'echo_group' ) ) );
+ ->will( $this->returnValue( array( $group ) ) );
return $user;
}
diff --git a/tests/includes/mapper/NotificationMapperTest.php
b/tests/includes/mapper/NotificationMapperTest.php
index eac422c..224f9df 100644
--- a/tests/includes/mapper/NotificationMapperTest.php
+++ b/tests/includes/mapper/NotificationMapperTest.php
@@ -44,8 +44,13 @@
)
);
$notifMapper = new EchoNotificationMapper(
$this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
- $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '' );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '',
array() );
+ $this->assertEmpty( $res );
+
+ $notifMapper = new EchoNotificationMapper(
$this->mockMWEchoDbFactory( array ( 'select' => $dbResult ) ) );
+ $res = $notifMapper->fetchByUser( $this->mockUser(), 10, '',
array( 'test_event' ) );
$this->assertTrue( is_array( $res ) );
+ $this->assertGreaterThan( 0, count( $res ) );
foreach ( $res as $row ) {
$this->assertInstanceOf( 'EchoNotification', $row );
}
--
To view, visit https://gerrit.wikimedia.org/r/150697
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic685f7026ab9b41407b51317780bbfadd05bf9f1
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Echo
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>
Gerrit-Reviewer: Bsitu <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits