2016-01-15 22:11:33 +00:00
|
|
|
( function ( mw, $ ) {
|
|
|
|
/**
|
|
|
|
* Abstract notification API handler
|
|
|
|
*
|
|
|
|
* @abstract
|
|
|
|
* @class
|
|
|
|
*
|
|
|
|
* @constructor
|
2016-05-06 13:02:33 +00:00
|
|
|
* @param {mw.Api} api
|
2016-01-15 22:11:33 +00:00
|
|
|
* @param {Object} [config] Configuration object
|
|
|
|
* @cfg {number} [limit=25] The limit on how many notifications to fetch
|
|
|
|
* @cfg {string} [userLang=mw.config.get( 'wgUserLanguage' )] User language. Defaults
|
|
|
|
* to the default user language configuration settings.
|
|
|
|
*/
|
2016-05-06 13:02:33 +00:00
|
|
|
mw.echo.api.APIHandler = function MwEchoApiAPIHandler( api, config ) {
|
2016-01-15 22:11:33 +00:00
|
|
|
config = config || {};
|
|
|
|
|
|
|
|
this.fetchNotificationsPromise = {};
|
|
|
|
this.apiErrorState = {};
|
|
|
|
|
|
|
|
this.limit = config.limit || 25;
|
|
|
|
this.userLang = config.userLang || mw.config.get( 'wgUserLanguage' );
|
|
|
|
|
2016-05-06 13:02:33 +00:00
|
|
|
this.api = api;
|
2016-01-15 22:11:33 +00:00
|
|
|
|
|
|
|
// Map the logical type to the type
|
|
|
|
// that the API recognizes
|
|
|
|
this.normalizedType = {
|
|
|
|
message: 'message',
|
|
|
|
alert: 'alert',
|
|
|
|
all: 'message|alert'
|
|
|
|
};
|
|
|
|
|
|
|
|
// Parameters that are sent through
|
|
|
|
// to the 'fetch notification' promise
|
|
|
|
// per type
|
|
|
|
this.typeParams = {
|
|
|
|
message: {},
|
|
|
|
alert: {},
|
|
|
|
all: {}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Setup */
|
|
|
|
|
|
|
|
OO.initClass( mw.echo.api.APIHandler );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch notifications from the API.
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type
|
2016-05-19 20:49:09 +00:00
|
|
|
* @param {Object} [overrideParams] An object defining parameters to override in the API
|
|
|
|
* fetching call.
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that resolves with an object containing the
|
|
|
|
* notification items
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.fetchNotifications = null;
|
|
|
|
|
2016-08-05 21:44:55 +00:00
|
|
|
/**
|
|
|
|
* Send a general query to the API. This is mostly for dynamic actions
|
|
|
|
* where other extensions may set up API actions that are unique and
|
|
|
|
* unanticipated.
|
|
|
|
*
|
|
|
|
* @param {Object} data Data object about the operation.
|
|
|
|
* @param {string} [data.tokenType=csrf] Token type, 'csrf', 'watch', etc
|
|
|
|
* @param {Object} [data.params] Parameters to pass to the API call
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved when the action
|
|
|
|
* is complete
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.queryAPI = function ( data ) {
|
|
|
|
return this.api.postWithToken( data.tokenType || 'csrf', data.params );
|
|
|
|
};
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
/**
|
|
|
|
* Fetch all pages with unread notifications in them per wiki
|
|
|
|
*
|
|
|
|
* @param {string|string[]} [sources=*] Requested sources. If not given
|
|
|
|
* or if a '*' is given, all available sources will be queried
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved with an object
|
|
|
|
* of pages with the number of unread notifications per wiki
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.fetchUnreadNotificationPages = function ( sources ) {
|
|
|
|
var params = {
|
2016-11-18 21:16:43 +00:00
|
|
|
action: 'query',
|
|
|
|
meta: 'unreadnotificationpages',
|
|
|
|
uselang: this.userLang,
|
|
|
|
unpgrouppages: true
|
|
|
|
};
|
2016-05-31 22:32:16 +00:00
|
|
|
|
|
|
|
if ( !sources || sources === '*' ) {
|
|
|
|
params.unpwikis = '*';
|
|
|
|
} else {
|
|
|
|
sources = Array.isArray( sources ) ? sources : [ sources ];
|
|
|
|
params.unpwikis = sources.join( '|' );
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.api.get( params );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the given source is local
|
|
|
|
*
|
|
|
|
* @param {string|string[]} sources Source names
|
|
|
|
* @return {boolean} Source is local
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.isSourceLocal = function ( sources ) {
|
|
|
|
return Array.isArray( sources ) ?
|
|
|
|
(
|
|
|
|
sources.indexOf( 'local' ) !== -1 ||
|
|
|
|
sources.indexOf( mw.config.get( 'wgDBname' ) ) !== -1
|
|
|
|
) :
|
|
|
|
(
|
|
|
|
sources === 'local' ||
|
|
|
|
sources === mw.config.get( 'wgDBname' )
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2016-01-15 22:11:33 +00:00
|
|
|
/**
|
|
|
|
* Create a new fetchNotifications promise that queries the API and overrides
|
|
|
|
* the cached promise.
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type
|
2016-05-04 00:50:27 +00:00
|
|
|
* @param {string[]} [sources] An array of sources to query
|
2016-05-19 20:49:09 +00:00
|
|
|
* @param {Object} [overrideParams] An object defining parameters to override in the API
|
|
|
|
* fetching call.
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved when notifications are
|
|
|
|
* fetched from the API.
|
2016-01-15 22:11:33 +00:00
|
|
|
*/
|
2016-05-19 20:49:09 +00:00
|
|
|
mw.echo.api.APIHandler.prototype.createNewFetchNotificationPromise = function ( type, sources, overrideParams ) {
|
2016-11-18 21:16:43 +00:00
|
|
|
var fetchNotifPromise,
|
2016-05-19 20:49:09 +00:00
|
|
|
fetchingSource = 'local',
|
2016-05-04 00:50:27 +00:00
|
|
|
me = this,
|
2016-01-15 22:11:33 +00:00
|
|
|
params = $.extend( {
|
|
|
|
action: 'query',
|
2017-09-13 22:18:07 +00:00
|
|
|
formatversion: 2,
|
2016-01-15 22:11:33 +00:00
|
|
|
meta: 'notifications',
|
|
|
|
notsections: this.normalizedType[ type ],
|
|
|
|
notformat: 'model',
|
|
|
|
notlimit: this.limit,
|
2016-07-25 23:03:29 +00:00
|
|
|
notprop: 'list|count|seenTime',
|
2016-01-15 22:11:33 +00:00
|
|
|
uselang: this.userLang
|
|
|
|
}, this.getTypeParams( type ) );
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
if ( !this.isSourceLocal( sources ) ) {
|
2016-05-04 00:50:27 +00:00
|
|
|
params.notwikis = sources.join( '|' );
|
|
|
|
params.notfilter = '!read';
|
|
|
|
fetchingSource = 'foreign';
|
|
|
|
}
|
|
|
|
|
2016-05-19 20:49:09 +00:00
|
|
|
// Initialize the nested value if it doesn't yet exist
|
2016-05-04 00:50:27 +00:00
|
|
|
this.fetchNotificationsPromise[ type ] = this.fetchNotificationsPromise[ type ] || {};
|
2016-05-19 20:49:09 +00:00
|
|
|
me.apiErrorState[ type ] = me.apiErrorState[ type ] || {};
|
|
|
|
|
|
|
|
// Reset cached values
|
|
|
|
this.fetchNotificationsPromise[ type ][ fetchingSource ] = null;
|
|
|
|
this.apiErrorState[ type ][ fetchingSource ] = false;
|
|
|
|
|
|
|
|
// Create the fetch promise
|
|
|
|
fetchNotifPromise = this.api.get( $.extend( true, params, overrideParams ) );
|
|
|
|
|
|
|
|
// Only cache promises that don't have override params in them
|
|
|
|
if ( !overrideParams ) {
|
|
|
|
this.fetchNotificationsPromise[ type ][ fetchingSource ] = fetchNotifPromise;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fetchNotifPromise
|
2016-01-15 22:11:33 +00:00
|
|
|
.fail( function () {
|
|
|
|
// Mark API error state
|
2016-05-04 00:50:27 +00:00
|
|
|
me.apiErrorState[ type ][ fetchingSource ] = true;
|
2016-01-15 22:11:33 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the seen timestamp
|
|
|
|
*
|
2016-07-08 22:56:01 +00:00
|
|
|
* @param {string|string[]} [types] Notification type 'message', 'alert' or [ 'message', 'alert' ].
|
2016-07-22 18:59:10 +00:00
|
|
|
* @return {jQuery.Promise} A promise that resolves with the seen timestamp, as a full UTC
|
|
|
|
* ISO 8601 timestamp.
|
2016-01-15 22:11:33 +00:00
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.updateSeenTime = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark all notifications as read
|
|
|
|
*
|
|
|
|
* @param {string|string[]} type Notification type 'message', 'alert' or 'all'.
|
|
|
|
* @return {jQuery.Promise} A promise that resolves when all notifications
|
|
|
|
* are marked as read.
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.markAllRead = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark multiple notification items as read using specific IDs
|
|
|
|
*
|
|
|
|
* @abstract
|
|
|
|
* @param {string[]} itemIdArray An array of notification item IDs
|
2016-03-04 22:44:22 +00:00
|
|
|
* @param {boolean} [isRead] Item's new read state; true for marking the item
|
|
|
|
* as read, false for marking the item as unread
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that resolves when all given notifications
|
|
|
|
* are marked as read.
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.markItemsRead = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the read status of a notification item in the API
|
|
|
|
*
|
|
|
|
* @param {string} itemId Item id
|
2016-03-04 22:44:22 +00:00
|
|
|
* @param {boolean} [isRead] Item's new read state; true for marking the item
|
|
|
|
* as read, false for marking the item as unread
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that resolves when the notifications
|
|
|
|
* are marked as read.
|
|
|
|
*/
|
2016-03-04 22:44:22 +00:00
|
|
|
mw.echo.api.APIHandler.prototype.markItemRead = function ( itemId, isRead ) {
|
2016-03-14 22:23:08 +00:00
|
|
|
return this.markItemsRead( [ itemId ], isRead );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Query the API for unread count of the notifications in this model
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type 'message', 'alert' or 'all'.
|
|
|
|
* @return {jQuery.Promise} jQuery promise that's resolved when the unread count is fetched
|
|
|
|
* and the badge label is updated.
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.fetchUnreadCount = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether the model has an API error state flagged
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type, 'alert', 'message' or 'all'
|
2016-11-18 21:16:43 +00:00
|
|
|
* @param {string|string[]} sources Source names
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {boolean} The model is in API error state
|
|
|
|
*/
|
2016-05-04 00:50:27 +00:00
|
|
|
mw.echo.api.APIHandler.prototype.isFetchingErrorState = function ( type, sources ) {
|
|
|
|
var fetchingSource = 'local';
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
if ( !this.isSourceLocal( sources ) ) {
|
2016-05-04 00:50:27 +00:00
|
|
|
fetchingSource = 'foreign';
|
|
|
|
}
|
|
|
|
return !!( this.apiErrorState[ type ] && this.apiErrorState[ type ][ fetchingSource ] );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the fetch notifications promise
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type, 'alert', 'message' or 'all'
|
2016-05-19 20:49:09 +00:00
|
|
|
* @param {string|string[]} [sources] A name of a source or an array of sources to query
|
|
|
|
* @param {Object} [overrideParams] An object defining parameters to override in the API
|
|
|
|
* fetching call.
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} Promise that is resolved when notifications are
|
|
|
|
* fetched from the API.
|
|
|
|
*/
|
2016-05-19 20:49:09 +00:00
|
|
|
mw.echo.api.APIHandler.prototype.getFetchNotificationPromise = function ( type, sources, overrideParams ) {
|
2016-05-04 00:50:27 +00:00
|
|
|
var fetchingSource = 'local';
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
if ( !this.isSourceLocal( sources ) ) {
|
2016-05-04 00:50:27 +00:00
|
|
|
fetchingSource = 'foreign';
|
|
|
|
}
|
2016-05-19 20:49:09 +00:00
|
|
|
if ( overrideParams || !this.fetchNotificationsPromise[ type ] || !this.fetchNotificationsPromise[ type ][ fetchingSource ] ) {
|
|
|
|
this.createNewFetchNotificationPromise( type, sources, overrideParams );
|
2016-01-15 22:11:33 +00:00
|
|
|
}
|
2016-05-04 00:50:27 +00:00
|
|
|
return this.fetchNotificationsPromise[ type ][ fetchingSource ];
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the extra parameters for fetching notifications for a given
|
|
|
|
* notification type.
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type
|
|
|
|
* @return {Object} Extra API parameters for fetch notifications
|
|
|
|
*/
|
|
|
|
mw.echo.api.APIHandler.prototype.getTypeParams = function ( type ) {
|
|
|
|
return this.typeParams[ type ];
|
|
|
|
};
|
2016-11-18 21:16:43 +00:00
|
|
|
}( mediaWiki, jQuery ) );
|