2014-07-22 21:33:22 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An object that manages attributes of echo notifications: category, elegibility,
|
|
|
|
* group, section etc.
|
|
|
|
*/
|
|
|
|
class EchoAttributeManager {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $notifications;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $categories;
|
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
/**
|
|
|
|
* Notification section constant
|
|
|
|
*/
|
|
|
|
const ALERT = 'alert';
|
|
|
|
const MESSAGE = 'message';
|
|
|
|
const ALL = 'all';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notifications are broken down to two sections, default is alert
|
|
|
|
* @var array
|
|
|
|
*/
|
2015-10-01 13:48:52 +00:00
|
|
|
public static $sections = array(
|
2014-08-05 21:50:54 +00:00
|
|
|
self::ALERT,
|
|
|
|
self::MESSAGE
|
|
|
|
);
|
|
|
|
|
Allow certain users to be excluded
Right now, if certain users should be excluded, that would have
to be part of the user-locators already. This is annoying because
it's hard to write "generic" user locators when you want to exclude
just a couple of people in certain cases.
In Flow, for example, we have user-locators for users watching a
board or topic. We don't want to send the notification to people
that have also been mentioned in that post (they'll get a separate
notification). We could build that exception into those
user-locators, but then we couldn't re-use them in other places...
This basically means we couldn't use EchoUserLocator::locateUsersWatchingTitle,
we would have to roll our own that also excludes mentioned users.
Instead, this lets you add 'user-filters' (that functionality
actually exists already, but is not currently exposed), which
lists users to not send the notification to, even though they could
be in a user-locator.
Bug: T125428
Change-Id: Ifa0e2d3283f57624af4c5ec264f9f66223508e83
2016-02-02 13:16:39 +00:00
|
|
|
/**
|
|
|
|
* Names for keys in $wgEchoNotifications notification config
|
|
|
|
*/
|
|
|
|
const ATTR_LOCATORS = 'user-locators';
|
|
|
|
const ATTR_FILTERS = 'user-filters';
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
/**
|
2015-07-31 19:19:53 +00:00
|
|
|
* An EchoAttributeManager instance created from global variables
|
|
|
|
* @param EchoAttributeManager
|
2014-07-22 21:33:22 +00:00
|
|
|
*/
|
2015-07-31 19:19:53 +00:00
|
|
|
protected static $globalVarInstance = null;
|
2014-07-22 21:33:22 +00:00
|
|
|
|
|
|
|
/**
|
2015-07-31 19:19:53 +00:00
|
|
|
* @param array $notifications notification attributes
|
|
|
|
* @param array $categories notification categories
|
2014-07-22 21:33:22 +00:00
|
|
|
*/
|
|
|
|
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
|
2016-03-14 16:44:33 +00:00
|
|
|
if ( defined( 'MW_PHPUNIT_TEST' ) ) {
|
2014-07-22 21:33:22 +00:00
|
|
|
return new self( $wgEchoNotifications, $wgEchoNotificationCategories );
|
|
|
|
}
|
2015-07-31 19:19:53 +00:00
|
|
|
|
|
|
|
if ( self::$globalVarInstance === null ) {
|
|
|
|
self::$globalVarInstance = new self(
|
2014-07-22 21:33:22 +00:00
|
|
|
$wgEchoNotifications,
|
|
|
|
$wgEchoNotificationCategories
|
|
|
|
);
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2015-07-31 19:19:53 +00:00
|
|
|
return self::$globalVarInstance;
|
2014-07-22 21:33:22 +00:00
|
|
|
}
|
|
|
|
|
2014-07-29 23:54:00 +00:00
|
|
|
/**
|
Allow certain users to be excluded
Right now, if certain users should be excluded, that would have
to be part of the user-locators already. This is annoying because
it's hard to write "generic" user locators when you want to exclude
just a couple of people in certain cases.
In Flow, for example, we have user-locators for users watching a
board or topic. We don't want to send the notification to people
that have also been mentioned in that post (they'll get a separate
notification). We could build that exception into those
user-locators, but then we couldn't re-use them in other places...
This basically means we couldn't use EchoUserLocator::locateUsersWatchingTitle,
we would have to roll our own that also excludes mentioned users.
Instead, this lets you add 'user-filters' (that functionality
actually exists already, but is not currently exposed), which
lists users to not send the notification to, even though they could
be in a user-locator.
Bug: T125428
Change-Id: Ifa0e2d3283f57624af4c5ec264f9f66223508e83
2016-02-02 13:16:39 +00:00
|
|
|
* Get the user-locators|user-filters related to the provided event type
|
2014-07-29 23:54:00 +00:00
|
|
|
*
|
|
|
|
* @param string $type
|
Allow certain users to be excluded
Right now, if certain users should be excluded, that would have
to be part of the user-locators already. This is annoying because
it's hard to write "generic" user locators when you want to exclude
just a couple of people in certain cases.
In Flow, for example, we have user-locators for users watching a
board or topic. We don't want to send the notification to people
that have also been mentioned in that post (they'll get a separate
notification). We could build that exception into those
user-locators, but then we couldn't re-use them in other places...
This basically means we couldn't use EchoUserLocator::locateUsersWatchingTitle,
we would have to roll our own that also excludes mentioned users.
Instead, this lets you add 'user-filters' (that functionality
actually exists already, but is not currently exposed), which
lists users to not send the notification to, even though they could
be in a user-locator.
Bug: T125428
Change-Id: Ifa0e2d3283f57624af4c5ec264f9f66223508e83
2016-02-02 13:16:39 +00:00
|
|
|
* @param string $locator Either self::ATTR_LOCATORS or self::ATTR_FILTERS
|
2014-07-29 23:54:00 +00:00
|
|
|
* @return array
|
|
|
|
*/
|
Allow certain users to be excluded
Right now, if certain users should be excluded, that would have
to be part of the user-locators already. This is annoying because
it's hard to write "generic" user locators when you want to exclude
just a couple of people in certain cases.
In Flow, for example, we have user-locators for users watching a
board or topic. We don't want to send the notification to people
that have also been mentioned in that post (they'll get a separate
notification). We could build that exception into those
user-locators, but then we couldn't re-use them in other places...
This basically means we couldn't use EchoUserLocator::locateUsersWatchingTitle,
we would have to roll our own that also excludes mentioned users.
Instead, this lets you add 'user-filters' (that functionality
actually exists already, but is not currently exposed), which
lists users to not send the notification to, even though they could
be in a user-locator.
Bug: T125428
Change-Id: Ifa0e2d3283f57624af4c5ec264f9f66223508e83
2016-02-02 13:16:39 +00:00
|
|
|
public function getUserCallable( $type, $locator = self::ATTR_LOCATORS ) {
|
|
|
|
if ( isset( $this->notifications[$type][$locator] ) ) {
|
|
|
|
return (array)$this->notifications[$type][$locator];
|
2014-07-29 23:54:00 +00:00
|
|
|
} else {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
/**
|
|
|
|
* Get the uesr enabled events for the specified sections
|
|
|
|
* @param User
|
|
|
|
* @param string
|
|
|
|
* @param string[]
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getUserEnabledEventsbySections( User $user, $outputFormat, array $sections ) {
|
|
|
|
$events = array();
|
|
|
|
foreach ( $sections as $section ) {
|
|
|
|
$events = array_merge(
|
|
|
|
$events,
|
|
|
|
call_user_func(
|
|
|
|
array( $this, 'get' . ucfirst( $section ) . 'Events' )
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
return array_intersect(
|
|
|
|
$this->getUserEnabledEvents( $user, $outputFormat ),
|
|
|
|
$events
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
/**
|
|
|
|
* Get alert notification event. Notifications without a section attributes
|
|
|
|
* default to section alert
|
|
|
|
* @return array
|
|
|
|
*/
|
2014-08-05 21:50:54 +00:00
|
|
|
public function getAlertEvents() {
|
|
|
|
$events = array();
|
|
|
|
foreach ( $this->notifications as $event => $attribs ) {
|
|
|
|
if (
|
|
|
|
!isset( $attribs['section'] )
|
|
|
|
|| !in_array( $attribs['section'], self::$sections )
|
|
|
|
|| $attribs['section'] === 'alert'
|
|
|
|
) {
|
|
|
|
$events[] = $event;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
return $events;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get message notification event
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getMessageEvents() {
|
|
|
|
$events = array();
|
|
|
|
foreach ( $this->notifications as $event => $attribs ) {
|
|
|
|
if (
|
|
|
|
isset( $attribs['section'] )
|
|
|
|
&& $attribs['section'] === 'message'
|
|
|
|
) {
|
|
|
|
$events[] = $event;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
return $events;
|
2014-07-22 21:33:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
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 );
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
return 'other';
|
|
|
|
}
|
2014-08-05 21:50:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get notification section for a notification type
|
|
|
|
* @todo add a unit test case
|
2016-03-07 19:48:39 +00:00
|
|
|
* @param string $notificationType
|
2014-08-05 21:50:54 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getNotificationSection( $notificationType ) {
|
|
|
|
if ( isset( $this->notifications[$notificationType]['section'] ) ) {
|
|
|
|
return $this->notifications[$notificationType]['section'];
|
|
|
|
}
|
2015-10-01 13:48:52 +00:00
|
|
|
|
2014-08-05 21:50:54 +00:00
|
|
|
return 'alert';
|
|
|
|
}
|
|
|
|
|
2014-07-22 21:33:22 +00:00
|
|
|
}
|