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

Reply via email to