mediawiki-extensions-Echo/modules/api/mw.echo.api.APIHandler.js
Moriel Schottlender 3a710790d5 Add a SeenTimeModel to handle seenTime in sources
This organizes the operation of seenTime so we can store and
follow up on it based on different sources, as well as update
it correctly remotely when needed.

Change-Id: I629ecfc84999be998b45c9c7adb00ea7e3e51742
2016-07-15 11:25:38 -07:00

255 lines
7.9 KiB
JavaScript

( function ( mw, $ ) {
/**
* Abstract notification API handler
*
* @abstract
* @class
*
* @constructor
* @param {mw.Api} api
* @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.
*/
mw.echo.api.APIHandler = function MwEchoApiAPIHandler( api, config ) {
config = config || {};
this.fetchNotificationsPromise = {};
this.apiErrorState = {};
this.limit = config.limit || 25;
this.userLang = config.userLang || mw.config.get( 'wgUserLanguage' );
this.api = api;
// 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
* @param {Object} [overrideParams] An object defining parameters to override in the API
* fetching call.
* @return {jQuery.Promise} A promise that resolves with an object containing the
* notification items
*/
mw.echo.api.APIHandler.prototype.fetchNotifications = null;
/**
* 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 = {
action: 'query',
meta: 'unreadnotificationpages'
};
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' )
);
};
/**
* Create a new fetchNotifications promise that queries the API and overrides
* the cached promise.
*
* @param {string} type Notification type
* @param {string[]} [sources] An array of sources to query
* @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.
*/
mw.echo.api.APIHandler.prototype.createNewFetchNotificationPromise = function ( type, sources, overrideParams ) {
var apiErrState, fetchNotifPromise,
fetchingSource = 'local',
me = this,
params = $.extend( {
action: 'query',
meta: 'notifications',
notsections: this.normalizedType[ type ],
notformat: 'model',
notlimit: this.limit,
notprop: 'list|count',
uselang: this.userLang
}, this.getTypeParams( type ) );
if ( !this.isSourceLocal( sources ) ) {
params.notwikis = sources.join( '|' );
params.notfilter = '!read';
fetchingSource = 'foreign';
}
// Initialize the nested value if it doesn't yet exist
this.fetchNotificationsPromise[ type ] = this.fetchNotificationsPromise[ type ] || {};
me.apiErrorState[ type ] = me.apiErrorState[ type ] || {};
// Reset cached values
apiErrState = false;
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
.fail( function () {
// Mark API error state
me.apiErrorState[ type ][ fetchingSource ] = true;
} );
};
/**
* Update the seen timestamp
*
* @param {string|string[]} [types] Notification type 'message', 'alert' or [ 'message', 'alert' ].
* @return {jQuery.Promise} A promise that resolves with the seen timestamp
*/
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
* @param {boolean} [isRead] Item's new read state; true for marking the item
* as read, false for marking the item as unread
* @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
* @param {boolean} [isRead] Item's new read state; true for marking the item
* as read, false for marking the item as unread
* @return {jQuery.Promise} A promise that resolves when the notifications
* are marked as read.
*/
mw.echo.api.APIHandler.prototype.markItemRead = function ( itemId, isRead ) {
return this.markItemsRead( [ itemId ], isRead );
};
/**
* 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'
* @return {boolean} The model is in API error state
*/
mw.echo.api.APIHandler.prototype.isFetchingErrorState = function ( type, sources ) {
var fetchingSource = 'local';
if ( !this.isSourceLocal( sources ) ) {
fetchingSource = 'foreign';
}
return !!( this.apiErrorState[ type ] && this.apiErrorState[ type ][ fetchingSource ] );
};
/**
* Return the fetch notifications promise
*
* @param {string} type Notification type, 'alert', 'message' or 'all'
* @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.
* @return {jQuery.Promise} Promise that is resolved when notifications are
* fetched from the API.
*/
mw.echo.api.APIHandler.prototype.getFetchNotificationPromise = function ( type, sources, overrideParams ) {
var fetchingSource = 'local';
if ( !this.isSourceLocal( sources ) ) {
fetchingSource = 'foreign';
}
if ( overrideParams || !this.fetchNotificationsPromise[ type ] || !this.fetchNotificationsPromise[ type ][ fetchingSource ] ) {
this.createNewFetchNotificationPromise( type, sources, overrideParams );
}
return this.fetchNotificationsPromise[ type ][ fetchingSource ];
};
/**
* 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 ];
};
} )( mediaWiki, jQuery );