2018-11-12 13:56:38 +00:00
|
|
|
( function () {
|
2016-01-15 22:11:33 +00:00
|
|
|
/**
|
|
|
|
* A class defining Echo API instructions and network operations
|
|
|
|
*
|
2016-03-16 22:47:20 +00:00
|
|
|
* @class
|
|
|
|
*
|
2016-01-15 22:11:33 +00:00
|
|
|
* @constructor
|
2016-03-16 22:47:20 +00:00
|
|
|
* @param {Object} config Configuration options
|
2024-05-27 01:43:21 +00:00
|
|
|
* @param {number} [config.limit=25] Number of notifications to fetch
|
2016-01-15 22:11:33 +00:00
|
|
|
*/
|
2016-03-16 22:47:20 +00:00
|
|
|
mw.echo.api.EchoApi = function MwEchoApiEchoApi( config ) {
|
|
|
|
config = config || {};
|
|
|
|
|
|
|
|
this.network = new mw.echo.api.NetworkHandler( config );
|
2016-01-15 22:11:33 +00:00
|
|
|
|
|
|
|
this.fetchingPromise = null;
|
2016-03-16 22:47:20 +00:00
|
|
|
this.limit = config.limit || 25;
|
2016-06-22 18:45:58 +00:00
|
|
|
this.fetchingPrioritizer = new mw.echo.api.PromisePrioritizer();
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
OO.initClass( mw.echo.api.EchoApi );
|
|
|
|
|
2016-02-27 05:43:46 +00:00
|
|
|
/**
|
2016-05-19 20:49:09 +00:00
|
|
|
* Register a set of foreign sources.
|
2016-02-27 05:43:46 +00:00
|
|
|
*
|
|
|
|
* @param {Object} sources Object mapping source names to config objects
|
2016-05-31 22:32:16 +00:00
|
|
|
* @param {boolean} [unreadOnly=false] Fetch only unread notifications
|
|
|
|
* @param {number} [limit] Specific limit of notifications. Defaults to
|
|
|
|
* the default limit stated in the class.
|
2016-02-27 05:43:46 +00:00
|
|
|
*/
|
2016-05-31 22:32:16 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.registerForeignSources = function ( sources, unreadOnly, limit ) {
|
|
|
|
limit = limit || this.limit;
|
|
|
|
|
2024-06-03 12:22:48 +00:00
|
|
|
for ( const s in sources ) {
|
2016-05-31 22:32:16 +00:00
|
|
|
this.network.setApiHandler( s, new mw.echo.api.ForeignAPIHandler( sources[ s ].url, {
|
|
|
|
unreadOnly: !!unreadOnly,
|
|
|
|
limit: limit
|
|
|
|
} ) );
|
2016-02-27 05:43:46 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-05-19 20:49:09 +00:00
|
|
|
/**
|
|
|
|
* Register a set of local sources.
|
|
|
|
*
|
|
|
|
* @param {string[]} sources An array of source names
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.registerLocalSources = function ( sources ) {
|
2024-06-03 12:22:48 +00:00
|
|
|
const localHandler = this.network.getApiHandler( 'local' );
|
2016-05-19 20:49:09 +00:00
|
|
|
|
2024-06-03 12:22:48 +00:00
|
|
|
for ( let i = 0; i < sources.length; i++ ) {
|
2016-05-19 20:49:09 +00:00
|
|
|
this.network.setApiHandler( sources[ i ], localHandler );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-01-15 22:11:33 +00:00
|
|
|
/**
|
2016-05-31 22:32:16 +00:00
|
|
|
* Fetch all pages with unread notifications in them per wiki
|
|
|
|
*
|
|
|
|
* @param {string[]} [sources=all] Requested sources
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved with an object
|
2018-11-27 22:48:32 +00:00
|
|
|
* of pages with the number of unread notifications per wiki
|
2016-05-31 22:32:16 +00:00
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.fetchUnreadNotificationPages = function ( sources ) {
|
|
|
|
return this.network.getApiHandler( 'local' ).fetchUnreadNotificationPages( sources )
|
2024-06-03 12:26:18 +00:00
|
|
|
.then( ( data ) => OO.getProp( data, 'query', 'unreadnotificationpages' ) );
|
2016-05-31 22:32:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch notifications from a given source with given filters
|
2016-03-07 13:29:15 +00:00
|
|
|
*
|
2016-03-25 18:52:59 +00:00
|
|
|
* @param {string} type Notification type to fetch: 'alert', 'message', or 'all'
|
2016-05-31 22:32:16 +00:00
|
|
|
* @param {string} [source] The source from which to fetch the notifications.
|
2016-05-04 00:50:27 +00:00
|
|
|
* If not given, the local notifications will be fetched.
|
2016-05-31 22:32:16 +00:00
|
|
|
* @param {Object} [filters] Filter values
|
2016-03-25 18:47:00 +00:00
|
|
|
* @return {jQuery.Promise} Promise that is resolved with all notifications for the
|
2016-01-15 22:11:33 +00:00
|
|
|
* requested types.
|
|
|
|
*/
|
2016-05-31 22:32:16 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.fetchFilteredNotifications = function ( type, source, filters ) {
|
|
|
|
source = source || 'local';
|
|
|
|
|
2016-07-07 19:20:39 +00:00
|
|
|
if ( source === 'local' ) {
|
2016-05-31 22:32:16 +00:00
|
|
|
return this.fetchNotifications( type, source, true, filters );
|
|
|
|
} else {
|
|
|
|
return this.fetchNotificationsFromRemoteSource( type, source, true, filters );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert the filter object to the relevant API parameters.
|
|
|
|
*
|
|
|
|
* @param {Object} [filterObject] The filter object
|
|
|
|
* @param {string} [filterObject.continue] A continue variable
|
|
|
|
* defining the offset to fetch notifications
|
|
|
|
* @param {string} [filterObject.readState] Notification read
|
|
|
|
* state, 'all', 'read' or 'unread'
|
2016-07-07 23:29:40 +00:00
|
|
|
* @param {boolean} [filterObject.unreadFirst] Fetch unread notifications
|
|
|
|
* first in the sorting order.
|
2016-08-04 14:42:11 +00:00
|
|
|
* @param {boolean} [filterObject.bundle] Bundle local notifications
|
2016-06-23 22:32:18 +00:00
|
|
|
* @param {string|string[]} [filterObject.titles] Requested titles. To request notifications with no title,
|
|
|
|
* use null (standalone or as an array element).
|
2016-05-31 22:32:16 +00:00
|
|
|
* @return {Object} API parameter definitions to override
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.convertFiltersToAPIParams = function ( filterObject ) {
|
2024-06-03 12:22:48 +00:00
|
|
|
const overrideParams = {};
|
2016-01-15 22:11:33 +00:00
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
filterObject = filterObject || {};
|
|
|
|
|
|
|
|
if ( filterObject.continue ) {
|
|
|
|
overrideParams.notcontinue = filterObject.continue;
|
2016-03-16 22:47:20 +00:00
|
|
|
}
|
|
|
|
|
2016-07-07 23:29:40 +00:00
|
|
|
if ( filterObject.unreadFirst ) {
|
|
|
|
overrideParams.notunreadfirst = 1;
|
|
|
|
}
|
|
|
|
|
2016-08-04 14:42:11 +00:00
|
|
|
if ( filterObject.bundle ) {
|
|
|
|
overrideParams.notbundle = 1;
|
|
|
|
}
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
if ( filterObject.readState && filterObject.readState !== 'all' ) {
|
|
|
|
overrideParams.notfilter = filterObject.readState === 'read' ?
|
2016-03-16 22:47:20 +00:00
|
|
|
'read' :
|
|
|
|
'!read';
|
|
|
|
}
|
|
|
|
|
2016-05-31 22:32:16 +00:00
|
|
|
if ( filterObject.titles ) {
|
2024-06-03 12:22:48 +00:00
|
|
|
const titles = Array.isArray( filterObject.titles ) ? filterObject.titles : [ filterObject.titles ];
|
2016-06-23 22:32:18 +00:00
|
|
|
if ( titles.indexOf( null ) !== -1 ) {
|
|
|
|
// Map null to '[]'
|
|
|
|
titles.splice( titles.indexOf( null ), 1, '[]' );
|
|
|
|
}
|
2023-04-11 18:55:09 +00:00
|
|
|
overrideParams.nottitles = titles;
|
2016-05-31 22:32:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return overrideParams;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch remote notifications from a given source. This skips the local fetching that is
|
|
|
|
* usually done and calls the remote wiki directly.
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type to fetch: 'alert', 'message', or 'all'
|
|
|
|
* @param {string|string[]} [source] The source from which to fetch the notifications.
|
|
|
|
* If not given, the local notifications will be fetched.
|
|
|
|
* @param {boolean} [isForced] Force a refresh on the fetch notifications promise
|
|
|
|
* @param {Object} [filters] Filter values
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved with all notifications for the
|
|
|
|
* requested types.
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.fetchNotificationsFromRemoteSource = function ( type, source, isForced, filters ) {
|
2024-06-03 12:22:48 +00:00
|
|
|
const handler = this.network.getApiHandler( source );
|
2016-05-31 22:32:16 +00:00
|
|
|
|
|
|
|
if ( !handler ) {
|
|
|
|
return $.Deferred().reject().promise();
|
|
|
|
}
|
|
|
|
|
2016-06-22 18:45:58 +00:00
|
|
|
return this.fetchingPrioritizer.prioritize( handler.fetchNotifications(
|
2016-05-31 22:32:16 +00:00
|
|
|
type,
|
|
|
|
// For the remote source, we are fetching 'local' notifications
|
|
|
|
'local',
|
|
|
|
!!isForced,
|
|
|
|
this.convertFiltersToAPIParams( filters )
|
2016-06-22 18:45:58 +00:00
|
|
|
) )
|
2024-06-03 12:26:18 +00:00
|
|
|
.then( ( result ) => OO.getProp( result.query, 'notifications' ) );
|
2016-05-31 22:32:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch notifications from the server based on type
|
|
|
|
*
|
|
|
|
* @param {string} type Notification type to fetch: 'alert', 'message', or 'all'
|
|
|
|
* @param {string|string[]} [sources] The source from which to fetch the notifications.
|
|
|
|
* If not given, the local notifications will be fetched.
|
|
|
|
* @param {boolean} [isForced] Force a refresh on the fetch notifications promise
|
|
|
|
* @param {Object} [filters] Filter values
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved with all notifications for the
|
|
|
|
* requested types.
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.fetchNotifications = function ( type, sources, isForced, filters ) {
|
|
|
|
sources = Array.isArray( sources ) ?
|
|
|
|
sources :
|
|
|
|
sources ?
|
|
|
|
[ sources ] :
|
|
|
|
'local';
|
|
|
|
|
2016-06-22 18:45:58 +00:00
|
|
|
return this.fetchingPrioritizer.prioritize( this.network.getApiHandler( 'local' ).fetchNotifications(
|
2016-05-31 22:32:16 +00:00
|
|
|
type,
|
|
|
|
sources,
|
|
|
|
isForced,
|
|
|
|
this.convertFiltersToAPIParams( filters )
|
2016-06-22 18:45:58 +00:00
|
|
|
) )
|
2024-06-03 12:26:18 +00:00
|
|
|
.then( ( result ) => OO.getProp( result.query, 'notifications' ) );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch notifications from several sources
|
|
|
|
*
|
|
|
|
* @param {string[]} sourceArray An array of sources to fetch from the group
|
|
|
|
* @param {string} type Notification type
|
2016-08-04 14:42:11 +00:00
|
|
|
* @param {boolean} bundle Bundle local notifications
|
2016-04-10 13:31:02 +00:00
|
|
|
* @return {jQuery.Promise} A promise that resolves with an object that maps wiki
|
|
|
|
* names to an array of their items' API data objects.
|
2016-01-15 22:11:33 +00:00
|
|
|
*/
|
2016-08-04 14:42:11 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.fetchNotificationGroups = function ( sourceArray, type, bundle ) {
|
2024-06-03 12:22:48 +00:00
|
|
|
const overrideParams = { notcrosswikisummary: false, notbundle: bundle };
|
2016-06-07 20:08:16 +00:00
|
|
|
return this.network.getApiHandler( 'local' ).fetchNotifications( type, sourceArray, true, overrideParams )
|
2024-06-03 12:26:18 +00:00
|
|
|
.then( ( result ) => {
|
2024-06-03 12:22:48 +00:00
|
|
|
const items = OO.getProp( result, 'query', 'notifications', 'list' ),
|
2016-04-10 13:31:02 +00:00
|
|
|
groups = {};
|
|
|
|
|
|
|
|
// Split the items to groups
|
2024-06-03 12:22:48 +00:00
|
|
|
for ( let i = 0; i < items.length; i++ ) {
|
2016-04-10 13:31:02 +00:00
|
|
|
groups[ items[ i ].wiki ] = groups[ items[ i ].wiki ] || [];
|
|
|
|
groups[ items[ i ].wiki ].push( items[ i ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return groups;
|
2016-05-04 00:50:27 +00:00
|
|
|
} );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark items as read in the API.
|
|
|
|
*
|
|
|
|
* @param {string[]} itemIds An array of item IDs to mark as read
|
|
|
|
* @param {string} source The source that these items belong to
|
2016-03-04 22:44:22 +00:00
|
|
|
* @param {boolean} [isRead] The read state of the item; 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 is resolved when the operation
|
|
|
|
* is complete, with the number of unread notifications still remaining
|
|
|
|
* for that type in the given source
|
|
|
|
*/
|
2016-03-04 22:44:22 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.markItemsRead = function ( itemIds, source, isRead ) {
|
2018-09-03 16:31:01 +00:00
|
|
|
// markasread is proxied via the local API
|
|
|
|
return this.network.getApiHandler( 'local' ).markItemsRead( source, itemIds, isRead );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark all notifications for a given type as read in the given source.
|
|
|
|
*
|
2016-03-25 18:47:00 +00:00
|
|
|
* @param {string} source Symbolic name of notifications source
|
|
|
|
* @param {string} type Notifications type
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that is resolved when the operation
|
|
|
|
* is complete, with the number of unread notifications still remaining
|
|
|
|
* for that type in the given source
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.markAllRead = function ( source, type ) {
|
2018-09-03 16:31:01 +00:00
|
|
|
// markasread is proxied via the local API
|
|
|
|
return this.network.getApiHandler( 'local' ).markAllRead( source, type );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetch the number of unread notifications for the given type in the given
|
|
|
|
* source.
|
|
|
|
*
|
|
|
|
* @param {string} source Notifications source
|
|
|
|
* @param {string} type Notification type
|
2016-06-29 23:36:03 +00:00
|
|
|
* @param {boolean} [localOnly] Fetches only the count of local notifications,
|
|
|
|
* and ignores cross-wiki notifications.
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that is resolved with the number of
|
|
|
|
* unread notifications for the given type and source.
|
|
|
|
*/
|
2016-06-29 23:36:03 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.fetchUnreadCount = function ( source, type, localOnly ) {
|
|
|
|
return this.network.getApiHandler( source ).fetchUnreadCount( type, localOnly );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2016-09-13 23:18:29 +00:00
|
|
|
* Update the seenTime property for the given type.
|
|
|
|
* We only need to update this in a single source for the seenTime
|
|
|
|
* to be updated globally - but we will let the consumer of
|
|
|
|
* this method override the choice of which source to update.
|
2016-01-15 22:11:33 +00:00
|
|
|
*
|
2016-07-08 22:56:01 +00:00
|
|
|
* @param {string} [type='alert,message'] Notification type
|
|
|
|
* @param {string} [source='local'] Notification source
|
2016-01-15 22:11:33 +00:00
|
|
|
* @return {jQuery.Promise} A promise that is resolved when the operation is complete.
|
|
|
|
*/
|
2016-07-08 22:56:01 +00:00
|
|
|
mw.echo.api.EchoApi.prototype.updateSeenTime = function ( type, source ) {
|
|
|
|
source = source || 'local';
|
|
|
|
type = type || [ 'alert', 'message' ];
|
2016-09-13 23:18:29 +00:00
|
|
|
|
2016-01-15 22:11:33 +00:00
|
|
|
return this.network.getApiHandler( source ).updateSeenTime( type );
|
|
|
|
};
|
|
|
|
|
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} params API parameters
|
|
|
|
* @param {string} [source='local'] Requested source to query
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved when the action
|
|
|
|
* is complete
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.queryAPI = function ( params, source ) {
|
|
|
|
source = source || 'local';
|
|
|
|
return this.network.getApiHandler( source )
|
|
|
|
.queryAPI( params );
|
|
|
|
};
|
|
|
|
|
2016-01-15 22:11:33 +00:00
|
|
|
/**
|
|
|
|
* Check whether the API promise for fetch notification is in an error
|
|
|
|
* state for the given source and notification type.
|
|
|
|
*
|
|
|
|
* @param {string} source Notification source.
|
|
|
|
* @param {string} type Notification type
|
2016-03-25 18:47:00 +00:00
|
|
|
* @return {boolean} The API response for fetching notification has
|
2016-01-15 22:11:33 +00:00
|
|
|
* resolved in an error state, or is rejected.
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.isFetchingErrorState = function ( source, type ) {
|
2016-05-04 00:50:27 +00:00
|
|
|
return this.network.getApiHandler( source ).isFetchingErrorState( type, [ source ] );
|
2016-01-15 22:11:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the fetch notifications promise active for the current source and type.
|
|
|
|
*
|
|
|
|
* @param {string} source Notification source.
|
|
|
|
* @param {string} type Notification type
|
|
|
|
* @return {jQuery.Promise} Promise that is resolved when notifications are
|
|
|
|
* fetched from the API.
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.getFetchNotificationPromise = function ( source, type ) {
|
|
|
|
return this.network.getApiHandler( source ).getFetchNotificationPromise( type );
|
|
|
|
};
|
|
|
|
|
2016-05-31 00:12:31 +00:00
|
|
|
/**
|
|
|
|
* Get the set limit for fetching notifications per request
|
|
|
|
*
|
|
|
|
* @return {number} Limit of notifications per request
|
|
|
|
*/
|
|
|
|
mw.echo.api.EchoApi.prototype.getLimit = function () {
|
|
|
|
return this.limit;
|
|
|
|
};
|
2018-11-12 13:56:38 +00:00
|
|
|
}() );
|