2012-04-27 15:14:24 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
class EchoNotificationController {
|
|
|
|
/**
|
2013-01-15 23:21:39 +00:00
|
|
|
* Retrieves number of unread notifications that a user has, would return
|
|
|
|
* $wgEchoMaxNotificationCount + 1 at most
|
2012-04-27 15:14:24 +00:00
|
|
|
*
|
|
|
|
* @param $user User object to check notifications for
|
2012-09-02 09:30:38 +00:00
|
|
|
* @param $cached bool Set to false to bypass the cache.
|
2012-12-19 02:16:52 +00:00
|
|
|
* @param $dbSource string use master or slave database to pull count
|
2012-04-27 15:14:24 +00:00
|
|
|
* @return Integer: Number of unread notifications.
|
|
|
|
*/
|
2012-12-19 02:16:52 +00:00
|
|
|
public static function getNotificationCount( $user, $cached = true, $dbSource = DB_SLAVE ) {
|
2013-01-15 23:21:39 +00:00
|
|
|
global $wgMemc, $wgEchoBackend, $wgEchoConfig;
|
2012-04-27 15:14:24 +00:00
|
|
|
|
2012-12-07 01:08:33 +00:00
|
|
|
if ( $user->isAnon() ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
$memcKey = wfMemcKey( 'echo-notification-count', $user->getId(), $wgEchoConfig['version'] );
|
2012-04-27 15:14:24 +00:00
|
|
|
|
2012-08-30 16:04:39 +00:00
|
|
|
if ( $cached && $wgMemc->get( $memcKey ) !== false ) {
|
|
|
|
return $wgMemc->get( $memcKey );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
$count = $wgEchoBackend->getNotificationCount( $user, $dbSource );
|
2012-11-13 23:06:11 +00:00
|
|
|
|
2012-08-15 15:36:57 +00:00
|
|
|
$wgMemc->set( $memcKey, $count, 86400 );
|
2012-04-27 15:14:24 +00:00
|
|
|
|
|
|
|
return $count;
|
|
|
|
}
|
|
|
|
|
2013-04-28 18:07:28 +00:00
|
|
|
/**
|
|
|
|
* 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 );
|
|
|
|
}
|
|
|
|
|
2013-01-17 00:31:56 +00:00
|
|
|
/**
|
|
|
|
* See if a user is eligible to recieve a certain type of notification
|
|
|
|
* (based on user groups, not user preferences)
|
|
|
|
*
|
|
|
|
* @param $user User object
|
2013-02-16 02:20:34 +00:00
|
|
|
* @param $notificationType string A notification type defined in $wgEchoNotifications
|
2013-01-17 00:31:56 +00:00
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public static function getNotificationEligibility( $user, $notificationType ) {
|
2013-03-07 20:48:14 +00:00
|
|
|
$category = self::getNotificationCategory( $notificationType );
|
|
|
|
return self::getCategoryEligibility( $user, $category );
|
2013-02-16 02:20:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
2013-01-17 00:31:56 +00:00
|
|
|
$usersGroups = $user->getGroups();
|
2013-02-16 02:20:34 +00:00
|
|
|
if ( isset( $wgEchoNotificationCategories[$category]['usergroups'] ) ) {
|
|
|
|
$allowedGroups = $wgEchoNotificationCategories[$category]['usergroups'];
|
2013-01-17 00:31:56 +00:00
|
|
|
if ( !array_intersect( $usersGroups, $allowedGroups ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-16 02:20:34 +00:00
|
|
|
/**
|
|
|
|
* 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 ) {
|
2013-03-07 20:48:14 +00:00
|
|
|
$category = self::getNotificationCategory( $notificationType );
|
2013-03-09 00:32:28 +00:00
|
|
|
return self::getCategoryPriority( $category );
|
2013-02-16 02:20:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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';
|
|
|
|
}
|
|
|
|
|
2012-11-13 23:06:11 +00:00
|
|
|
/**
|
|
|
|
* Retrieves formatted number of unread notifications that a user has.
|
|
|
|
*
|
|
|
|
* @param $user User object to check notifications for
|
|
|
|
* @param $cached bool Set to false to bypass the cache.
|
2012-12-19 02:16:52 +00:00
|
|
|
* @param $dbSource string use master or slave database to pull count
|
2012-11-13 23:06:11 +00:00
|
|
|
* @return String: Number of unread notifications.
|
|
|
|
*/
|
2012-12-19 02:16:52 +00:00
|
|
|
public static function getFormattedNotificationCount( $user, $cached = true, $dbSource = DB_SLAVE ) {
|
2012-11-13 23:06:11 +00:00
|
|
|
return self::formatNotificationCount(
|
2012-12-19 02:16:52 +00:00
|
|
|
self::getNotificationCount( $user, $cached, $dbSource )
|
2012-11-13 23:06:11 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Format the notification count with Language::formatNum(). In addition, for large count,
|
|
|
|
* return abbreviated version, e.g. 99+
|
|
|
|
* @param $count int
|
|
|
|
* @return string - formatted number
|
|
|
|
*/
|
|
|
|
public static function formatNotificationCount( $count ) {
|
|
|
|
global $wgLang, $wgEchoMaxNotificationCount;
|
|
|
|
|
|
|
|
if ( $count > $wgEchoMaxNotificationCount ) {
|
|
|
|
$count = wfMessage(
|
|
|
|
'echo-notification-count',
|
|
|
|
$wgLang->formatNum( $wgEchoMaxNotificationCount )
|
|
|
|
)->escaped();
|
|
|
|
} else {
|
|
|
|
$count = $wgLang->formatNum( $count );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $count;
|
|
|
|
}
|
|
|
|
|
2012-04-27 15:14:24 +00:00
|
|
|
/**
|
|
|
|
* Mark one or more notifications read for a user.
|
|
|
|
*
|
|
|
|
* @param $user User object to mark items read for.
|
|
|
|
* @param $eventIDs Array of event IDs to mark read
|
|
|
|
*/
|
|
|
|
public static function markRead( $user, $eventIDs ) {
|
2013-01-15 23:21:39 +00:00
|
|
|
global $wgEchoBackend;
|
2012-04-27 15:14:24 +00:00
|
|
|
|
|
|
|
$eventIDs = array_filter( (array)$eventIDs, 'is_numeric' );
|
2013-05-08 21:24:47 +00:00
|
|
|
if ( !$eventIDs || wfReadOnly() ) {
|
2013-01-15 23:21:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
$wgEchoBackend->markRead( $user, $eventIDs );
|
2012-12-19 02:16:52 +00:00
|
|
|
self::resetNotificationCount( $user, DB_MASTER );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2013-04-17 01:00:21 +00:00
|
|
|
/**
|
|
|
|
* @param $user User to mark all notifications read for
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public static function markAllRead( $user ) {
|
|
|
|
global $wgEchoBackend, $wgEchoMaxNotificationCount;
|
|
|
|
|
2013-05-08 21:24:47 +00:00
|
|
|
if ( wfReadOnly() ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-17 01:00:21 +00:00
|
|
|
$notificationCount = self::getNotificationCount( $user );
|
|
|
|
// Only update all the unread notifications if it isn't a huge number.
|
|
|
|
// TODO: Implement batched jobs it's over the maximum.
|
|
|
|
if ( $notificationCount <= $wgEchoMaxNotificationCount ) {
|
|
|
|
$wgEchoBackend->markAllRead( $user );
|
|
|
|
self::resetNotificationCount( $user, DB_MASTER );
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-27 15:14:24 +00:00
|
|
|
/**
|
|
|
|
* Recalculates the number of notifications that a user has.
|
|
|
|
*
|
|
|
|
* @param $user User object
|
2012-12-19 02:16:52 +00:00
|
|
|
* @param $dbSource string use master or slave database to pull count
|
2012-04-27 15:14:24 +00:00
|
|
|
*/
|
2012-12-19 02:16:52 +00:00
|
|
|
public static function resetNotificationCount( $user, $dbSource = DB_SLAVE ) {
|
|
|
|
self::getNotificationCount( $user, false, $dbSource );
|
2013-04-02 20:37:00 +00:00
|
|
|
$user->invalidateCache();
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processes notifications for a newly-created EchoEvent
|
2012-08-31 21:50:46 +00:00
|
|
|
*
|
2012-04-27 15:14:24 +00:00
|
|
|
* @param $event EchoEvent to do notifications for
|
2012-09-02 09:30:38 +00:00
|
|
|
* @param $defer bool Defer to job queue
|
2012-04-27 15:14:24 +00:00
|
|
|
*/
|
2012-06-06 07:04:28 +00:00
|
|
|
public static function notify( $event, $defer = true ) {
|
|
|
|
if ( $defer ) {
|
|
|
|
$title = $event->getTitle() ? $event->getTitle() : Title::newMainPage();
|
|
|
|
|
2012-08-30 16:04:39 +00:00
|
|
|
$job = new EchoNotificationJob( $title, array( 'event' => $event ) );
|
2012-06-06 07:04:28 +00:00
|
|
|
$job->insert();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-01 01:09:40 +00:00
|
|
|
// Check if the event object has valid event type. Events with invalid
|
|
|
|
// event types left in the job queue should not be processed
|
2012-11-13 23:06:11 +00:00
|
|
|
if ( !$event->isEnabledEvent() ) {
|
2013-03-01 01:09:40 +00:00
|
|
|
return;
|
2012-11-13 23:06:11 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
// Only send web notification for welcome event
|
|
|
|
if ( $event->getType() == 'welcome' ) {
|
2013-02-14 20:02:45 +00:00
|
|
|
self::doNotification( $event, $event->getAgent(), 'web' );
|
2012-08-31 23:35:16 +00:00
|
|
|
} else {
|
2013-01-15 23:21:39 +00:00
|
|
|
// Get the notification types for this event, eg, web/email
|
|
|
|
global $wgEchoDefaultNotificationTypes;
|
|
|
|
$notifyTypes = $wgEchoDefaultNotificationTypes['all'];
|
|
|
|
if ( isset( $wgEchoDefaultNotificationTypes[$event->getType()] ) ) {
|
|
|
|
$notifyTypes = array_merge( $notifyTypes, $wgEchoDefaultNotificationTypes[$event->getType()] );
|
|
|
|
}
|
|
|
|
$notifyTypes = array_keys( array_filter( $notifyTypes ) );
|
2012-04-27 15:14:24 +00:00
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
$users = self::getUsersToNotifyForEvent( $event );
|
2013-03-12 22:52:00 +00:00
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
foreach ( $users as $user ) {
|
2013-03-12 22:52:00 +00:00
|
|
|
// Notification should not be sent to anonymous user
|
|
|
|
if ( $user->isAnon() ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
wfRunHooks( 'EchoGetNotificationTypes', array( $user, $event, &$notifyTypes ) );
|
2012-04-27 15:14:24 +00:00
|
|
|
|
2012-08-31 23:35:16 +00:00
|
|
|
foreach ( $notifyTypes as $type ) {
|
|
|
|
self::doNotification( $event, $user, $type );
|
|
|
|
}
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Processes a single notification for an EchoEvent
|
|
|
|
*
|
2012-09-02 09:30:38 +00:00
|
|
|
* @param $event EchoEvent to do a notification for.
|
|
|
|
* @param $user User object to notify.
|
2012-11-16 21:03:57 +00:00
|
|
|
* @param $type string The type of notification delivery to process, e.g. 'email'.
|
2012-05-17 00:29:37 +00:00
|
|
|
* @throws MWException
|
2012-04-27 15:14:24 +00:00
|
|
|
*/
|
|
|
|
public static function doNotification( $event, $user, $type ) {
|
|
|
|
global $wgEchoNotifiers;
|
|
|
|
|
2012-08-31 21:50:46 +00:00
|
|
|
if ( !isset( $wgEchoNotifiers[$type] ) ) {
|
2012-04-27 15:14:24 +00:00
|
|
|
throw new MWException( "Invalid notification type $type" );
|
|
|
|
}
|
|
|
|
|
|
|
|
call_user_func_array( $wgEchoNotifiers[$type], array( $user, $event ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-01-15 23:21:39 +00:00
|
|
|
* Retrieves an array of User objects to be notified for an EchoEvent.
|
2012-08-31 21:50:46 +00:00
|
|
|
*
|
2013-01-15 23:21:39 +00:00
|
|
|
* @param $event EchoEvent to retrieve users to be notified for.
|
|
|
|
* @return Array of User objects
|
2012-04-27 15:14:24 +00:00
|
|
|
*/
|
2013-01-15 23:21:39 +00:00
|
|
|
protected static function getUsersToNotifyForEvent( $event ) {
|
|
|
|
$users = $notifyList = array();
|
2012-04-27 15:14:24 +00:00
|
|
|
wfRunHooks( 'EchoGetDefaultNotifiedUsers', array( $event, &$users ) );
|
2013-01-15 23:21:39 +00:00
|
|
|
// Make sure there is no duplicated users
|
|
|
|
foreach ( $users as $user ) {
|
|
|
|
$notifyList[$user->getId()] = $user;
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
// Don't notify the person who made the edit unless the event extra says to do so
|
2013-01-26 12:14:36 +00:00
|
|
|
$extra = $event->getExtra();
|
|
|
|
if ( ( !isset( $extra['notifyAgent'] ) || !$extra['notifyAgent'] ) && $event->getAgent() ) {
|
2013-01-15 23:21:39 +00:00
|
|
|
unset( $notifyList[$event->getAgent()->getId()] );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:21:39 +00:00
|
|
|
return $notifyList;
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats a notification
|
|
|
|
*
|
|
|
|
* @param $event EchoEvent that the notification is for.
|
2012-09-02 09:30:38 +00:00
|
|
|
* @param $user User to format the notification for.
|
2012-11-26 22:57:28 +00:00
|
|
|
* @param $format string The format to show the notification in: text, html, or email
|
2013-02-14 20:02:45 +00:00
|
|
|
* @param $type string The type of notification being distributed (e.g. email, web)
|
2012-11-26 22:57:28 +00:00
|
|
|
* @return string|array The formatted notification, or an array of subject
|
|
|
|
* and body (for emails), or an error message
|
2012-04-27 15:14:24 +00:00
|
|
|
*/
|
2013-02-14 20:02:45 +00:00
|
|
|
public static function formatNotification( $event, $user, $format = 'text', $type = 'web' ) {
|
2013-02-16 02:20:34 +00:00
|
|
|
global $wgEchoNotifications;
|
2012-04-27 15:14:24 +00:00
|
|
|
|
|
|
|
$eventType = $event->getType();
|
|
|
|
|
2013-02-16 02:20:34 +00:00
|
|
|
if ( isset( $wgEchoNotifications[$eventType] ) ) {
|
|
|
|
$params = $wgEchoNotifications[$eventType];
|
2012-08-30 16:04:39 +00:00
|
|
|
$notifier = EchoNotificationFormatter::factory( $params );
|
2012-04-27 15:14:24 +00:00
|
|
|
$notifier->setOutputFormat( $format );
|
|
|
|
|
2012-08-30 16:04:39 +00:00
|
|
|
return $notifier->format( $event, $user, $type );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
|
|
|
|
2012-08-01 18:20:21 +00:00
|
|
|
return Xml::tags( 'span', array( 'class' => 'error' ),
|
|
|
|
wfMessage( 'echo-error-no-formatter', $event->getType() )->escaped() );
|
2012-04-27 15:14:24 +00:00
|
|
|
}
|
2012-06-08 05:33:25 +00:00
|
|
|
}
|