Mooeypoo has uploaded a new change for review. https://gerrit.wikimedia.org/r/286782
Change subject: [wip] Adjust to local x-wiki call ...................................................................... [wip] Adjust to local x-wiki call Fetch x-wiki notifications by asking the local API, but still maintain the ability to send remote requests to the foreign wikis for mark as read operations. Change-Id: I48524cb9dff43257a401d7483e939edfb042b928 --- M modules/api/mw.echo.api.APIHandler.js M modules/api/mw.echo.api.EchoApi.js M modules/api/mw.echo.api.LocalAPIHandler.js M modules/viewmodel/mw.echo.dm.NotificationGroupItem.js M modules/viewmodel/mw.echo.dm.NotificationsModel.js 5 files changed, 128 insertions(+), 72 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Echo refs/changes/82/286782/1 diff --git a/modules/api/mw.echo.api.APIHandler.js b/modules/api/mw.echo.api.APIHandler.js index 0100e9a..9ab47e7 100644 --- a/modules/api/mw.echo.api.APIHandler.js +++ b/modules/api/mw.echo.api.APIHandler.js @@ -58,9 +58,11 @@ * the cached promise. * * @param {string} type Notification type + * @param {string[]} [sources] An array of sources to query */ - mw.echo.api.APIHandler.prototype.createNewFetchNotificationPromise = function ( type ) { - var me = this, + mw.echo.api.APIHandler.prototype.createNewFetchNotificationPromise = function ( type, sources ) { + var fetchingSource = 'local', + me = this, params = $.extend( { action: 'query', meta: 'notifications', @@ -72,11 +74,19 @@ uselang: this.userLang }, this.getTypeParams( type ) ); - this.apiErrorState[ type ] = false; - this.fetchNotificationsPromise[ type ] = this.api.get( params ) + if ( Array.isArray( sources ) && sources.indexOf( 'local' ) === -1 ) { + params.notwikis = sources.join( '|' ); + params.notfilter = '!read'; + fetchingSource = 'foreign'; + } + + this.apiErrorState[ type ] = this.apiErrorState[ type ] || {}; + this.apiErrorState[ type ][ fetchingSource ] = false; + this.fetchNotificationsPromise[ type ] = this.fetchNotificationsPromise[ type ] || {}; + this.fetchNotificationsPromise[ type ][ fetchingSource ] = this.api.get( params ) .fail( function () { // Mark API error state - me.apiErrorState[ type ] = true; + me.apiErrorState[ type ][ fetchingSource ] = true; } ); }; @@ -138,8 +148,13 @@ * @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 ) { - return !!this.apiErrorState[ type ]; + mw.echo.api.APIHandler.prototype.isFetchingErrorState = function ( type, sources ) { + var fetchingSource = 'local'; + + if ( Array.isArray( sources ) && sources.indexOf( 'local' ) === -1 ) { + fetchingSource = 'foreign'; + } + return !!( this.apiErrorState[ type ] && this.apiErrorState[ type ][ fetchingSource ] ); }; /** @@ -149,11 +164,16 @@ * @return {jQuery.Promise} Promise that is resolved when notifications are * fetched from the API. */ - mw.echo.api.APIHandler.prototype.getFetchNotificationPromise = function ( type ) { - if ( !this.fetchNotificationsPromise[ type ] ) { - this.createNewFetchNotificationPromise( type ); + mw.echo.api.APIHandler.prototype.getFetchNotificationPromise = function ( type, sources ) { + var fetchingSource = 'local'; + + if ( Array.isArray( sources ) && sources.indexOf( 'local' ) === -1 ) { + fetchingSource = 'foreign'; } - return this.fetchNotificationsPromise[ type ]; + if ( !this.fetchNotificationsPromise[ type ] || !this.fetchNotificationsPromise[ type ][ fetchingSource ] ) { + this.createNewFetchNotificationPromise( type, sources ); + } + return this.fetchNotificationsPromise[ type ][ fetchingSource ]; }; /** diff --git a/modules/api/mw.echo.api.EchoApi.js b/modules/api/mw.echo.api.EchoApi.js index 18fe23d..0fb4ebc 100644 --- a/modules/api/mw.echo.api.EchoApi.js +++ b/modules/api/mw.echo.api.EchoApi.js @@ -33,10 +33,14 @@ * @return {jQuery.Promise} Promise that is resolved with all notifications for the * requested types. */ - mw.echo.api.EchoApi.prototype.fetchNotifications = function ( type, source, isForced ) { - source = source || 'local'; + mw.echo.api.EchoApi.prototype.fetchNotifications = function ( type, sources, isForced ) { + sources = Array.isArray( sources ) ? + sources : + sources ? + [ sources ] : + null; - return this.network.getApiHandler( source ).fetchNotifications( type, isForced ) + return this.network.getApiHandler( 'local' ).fetchNotifications( type, sources, isForced ) .then( function ( result ) { return OO.getProp( result.query, 'notifications' ); } ); @@ -51,15 +55,10 @@ * fetchNotifications per each given source in the source array. */ mw.echo.api.EchoApi.prototype.fetchNotificationGroups = function ( sourceArray, type ) { - var i, promise, - promises = []; - - for ( i = 0; i < sourceArray.length; i++ ) { - promise = this.network.getApiHandler( sourceArray[ i ] ).fetchNotifications( type ); - promises.push( promise ); - } - - return mw.echo.api.NetworkHandler.static.waitForAllPromises( promises ); + return this.network.getApiHandler( 'local' ).fetchNotifications( type, sourceArray ) + .then( function ( result ) { + return OO.getProp( result, 'query', 'notifications', 'list' ); + } ); }; /** @@ -130,7 +129,7 @@ * resolved in an error state, or is rejected. */ mw.echo.api.EchoApi.prototype.isFetchingErrorState = function ( source, type ) { - return this.network.getApiHandler( source ).isFetchingErrorState( type ); + return this.network.getApiHandler( source ).isFetchingErrorState( type, [ source ] ); }; /** diff --git a/modules/api/mw.echo.api.LocalAPIHandler.js b/modules/api/mw.echo.api.LocalAPIHandler.js index 249b606..6712f1d 100644 --- a/modules/api/mw.echo.api.LocalAPIHandler.js +++ b/modules/api/mw.echo.api.LocalAPIHandler.js @@ -24,13 +24,13 @@ /** * @inheritdoc */ - mw.echo.api.LocalAPIHandler.prototype.fetchNotifications = function ( type, isForced ) { - if ( isForced || this.isFetchingErrorState( type ) ) { + mw.echo.api.LocalAPIHandler.prototype.fetchNotifications = function ( type, source, isForced ) { + if ( isForced || this.isFetchingErrorState( type, source ) ) { // Force new promise - this.createNewFetchNotificationPromise( type ); + this.createNewFetchNotificationPromise( type, source ); } - return this.getFetchNotificationPromise( type ); + return this.getFetchNotificationPromise( type, source ); }; /** @@ -81,7 +81,7 @@ /** * @inheritdoc */ - mw.echo.api.LocalAPIHandler.prototype.fetchUnreadCount = function ( type ) { + mw.echo.api.LocalAPIHandler.prototype.fetchUnreadCount = function ( type, source ) { var normalizedType = this.normalizedType[ type ], apiData = { action: 'query', diff --git a/modules/viewmodel/mw.echo.dm.NotificationGroupItem.js b/modules/viewmodel/mw.echo.dm.NotificationGroupItem.js index 6fddb78..0c9336a 100644 --- a/modules/viewmodel/mw.echo.dm.NotificationGroupItem.js +++ b/modules/viewmodel/mw.echo.dm.NotificationGroupItem.js @@ -122,22 +122,48 @@ mw.echo.dm.NotificationGroupItem.prototype.fetchAllNotificationsInGroups = function () { var notifModel, model = this, - fetchPromises = [], sourceKeys = Object.keys( this.sources ); return this.api.fetchNotificationGroups( sourceKeys, this.getType() ) - .then( function () { - var i; + .then( function ( itemsData ) { + var i, notifData, newNotifData, source, + modelItems = {}, + idArray = []; - for ( i = 0; i < sourceKeys.length; i++ ) { - notifModel = model.getItemById( sourceKeys[ i ] ); - if ( notifModel ) { - fetchPromises.push( notifModel.fetchNotifications() ); - } + for ( i = 0; i < itemsData.length; i++ ) { + notifData = itemsData[ i ]; + notifModel = model.getItemById( notifData.wiki ); + + newNotifData = notifModel.normalizeNotifData( notifData, false ); + + // Create an item for the notification model + modelItems[ notifData.wiki ] = modelItems[ notifData.wiki ] || []; + modelItems[ notifData.wiki ].push( + new mw.echo.dm.NotificationItem( + notifData.id, + newNotifData + ) + ); + + idArray.push( notifData.id ); } - // Wait for all fetch processes to finish before we resolve this promise - return mw.echo.api.NetworkHandler.static.waitForAllPromises( fetchPromises ); + // Reset all items + for ( source in modelItems ) { + notifModel = model.getItemById( source ); + // Superhack: We are mocking what the .fetchNotifications() + // is doing because the response from the API is now local + // rather than remote per model. This is a hack until the + // new MVC commit is merged, where it will be handled in the + // controller + notifModel.fetchingNotifications = true; + notifModel.clearItems(); + notifModel.fetchingNotifications = false; + // Add again to the model + notifModel.addItems( modelItems[ source ] ); + } + + return idArray; } ); }; diff --git a/modules/viewmodel/mw.echo.dm.NotificationsModel.js b/modules/viewmodel/mw.echo.dm.NotificationsModel.js index 4c77b37..e53c35c 100644 --- a/modules/viewmodel/mw.echo.dm.NotificationsModel.js +++ b/modules/viewmodel/mw.echo.dm.NotificationsModel.js @@ -450,6 +450,46 @@ return result; }; + mw.echo.dm.NotificationsModel.prototype.normalizeNotifData = function ( apiData, isGroupItem ) { + var content = apiData[ '*' ] || {}, + // Collect common data + notifData = { + read: !!apiData.read, + seen: !!apiData.read || apiData.timestamp.mw <= this.getSeenTime(), + timestamp: apiData.timestamp.utcmw, + category: apiData.category, + content: { + header: content.header, + body: content.body + }, + iconURL: content.iconUrl, + iconType: content.icon, + type: this.getType(), + foreign: this.isForeign(), + source: this.getSource(), + primaryUrl: OO.getProp( content.links, 'primary', 'url' ), + secondaryUrls: OO.getProp( content.links, 'secondary' ) || [] + }; + + if ( apiData.type === 'foreign' ) { + notifData = $.extend( true, {}, notifData, { + // This should probably be separated by bundled + // type. Some types don't have read messages, but + // some do + removeReadNotifications: true, + // Override the foreign flag to 'true' for cross-wiki + // notifications. + // For bundles that are not foreign (like regular + // bundles of notifications) this flag should be false + foreign: true, + type: notifData.section, + count: notifData.count + } ); + } + + return notifData; + }; + /** * Fetch notifications from the API and update the notifications list. * @@ -473,7 +513,7 @@ // Success function ( data ) { var i, notifData, - notificationModel, content, + notificationModel, newNotifData = {}, sources = {}, optionItems = [], @@ -483,26 +523,9 @@ for ( i = 0; i < data.list.length; i++ ) { notifData = data.list[ i ]; - content = notifData[ '*' ] || {}; + // content = notifData[ '*' ] || {}; - // Collect common data - newNotifData = { - read: !!notifData.read, - seen: !!notifData.read || notifData.timestamp.mw <= model.getSeenTime(), - timestamp: notifData.timestamp.utcmw, - category: notifData.category, - content: { - header: content.header, - body: content.body - }, - iconURL: content.iconUrl, - iconType: content.icon, - type: model.getType(), - foreign: model.isForeign(), - source: model.getSource(), - primaryUrl: OO.getProp( content.links, 'primary', 'url' ), - secondaryUrls: OO.getProp( content.links, 'secondary' ) || [] - }; + newNotifData = model.normalizeNotifData( notifData, notifData.type === 'foreign' ); if ( notifData.type === 'foreign' ) { // Register sources @@ -515,19 +538,7 @@ model.unreadCounter, sources, notifData.id, - $.extend( true, {}, newNotifData, { - // This should probably be separated by bundled - // type. Some types don't have read messages, but - // some do - removeReadNotifications: true, - // Override the foreign flag to 'true' for cross-wiki - // notifications. - // For bundles that are not foreign (like regular - // bundles of notifications) this flag should be false - foreign: true, - type: notifData.section, - count: notifData.count - } ) + newNotifData ); } else { notificationModel = new mw.echo.dm.NotificationItem( -- To view, visit https://gerrit.wikimedia.org/r/286782 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I48524cb9dff43257a401d7483e939edfb042b928 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Echo Gerrit-Branch: master Gerrit-Owner: Mooeypoo <mor...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits