summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--webclient/app-filter.js83
-rw-r--r--webclient/components/matrix/matrix-filter.js133
-rw-r--r--webclient/index.html1
-rw-r--r--webclient/recents/recents-controller.js11
-rw-r--r--webclient/recents/recents.html35
-rw-r--r--webclient/room/room-controller.js2
-rw-r--r--webclient/room/room.html2
-rw-r--r--webclient/settings/settings-controller.js75
-rw-r--r--webclient/settings/settings.html6
9 files changed, 217 insertions, 131 deletions
diff --git a/webclient/app-filter.js b/webclient/app-filter.js
index 27f435674f..ee9374668b 100644
--- a/webclient/app-filter.js
+++ b/webclient/app-filter.js
@@ -79,85 +79,4 @@ angular.module('matrixWebClient')
     return function(text) {
         return $sce.trustAsHtml(text);
     };
-}])
-
-// Compute the room name according to information we have
-.filter('roomName', ['$rootScope', 'matrixService', function($rootScope, matrixService) {
-    return function(room_id) {
-        var roomName;
-
-        // If there is an alias, use it
-        // TODO: only one alias is managed for now
-        var alias = matrixService.getRoomIdToAliasMapping(room_id);
-        if (alias) {
-            roomName = alias;
-        }
-
-        if (undefined === roomName) {
-            // Else, build the name from its users
-            var room = $rootScope.events.rooms[room_id];
-            if (room) {
-                var room_name_event = room["m.room.name"];
-
-                if (room_name_event) {
-                    roomName = room_name_event.content.name;
-                }
-                else if (room.members) {
-                    // Limit the room renaming to 1:1 room
-                    if (2 === Object.keys(room.members).length) {
-                        for (var i in room.members) {
-                            var member = room.members[i];
-                            if (member.state_key !== matrixService.config().user_id) {
-
-                                if (member.state_key in $rootScope.presence) {
-                                    // If the user is available in presence, use the displayname there
-                                    // as it is the most uptodate
-                                    roomName = $rootScope.presence[member.state_key].content.displayname;
-                                }
-                                else if (member.content.displayname) {
-                                    roomName = member.content.displayname;
-                                }
-                                else {
-                                    roomName = member.state_key;
-                                }
-                            }
-                        }
-                    }
-                    else if (1 === Object.keys(room.members).length) {
-                        // The other member may be in the invite list, get all invited users
-                        var invitedUserIDs = [];
-                        for (var i in room.messages) {
-                            var message = room.messages[i];
-                            if ("m.room.member" === message.type && "invite" === message.membership) {
-                                // Make sure there is no duplicate user
-                                if (-1 === invitedUserIDs.indexOf(message.state_key)) {
-                                    invitedUserIDs.push(message.state_key);
-                                }
-                            } 
-                        }
-                        
-                        // For now, only 1:1 room needs to be renamed. It means only 1 invited user
-                        if (1 === invitedUserIDs.length) {
-                            var userID = invitedUserIDs[0];
-
-                            // Try to resolve his displayname in presence global data
-                            if (userID in $rootScope.presence) {
-                                roomName = $rootScope.presence[userID].content.displayname;
-                            }
-                            else {
-                                roomName = userID;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        if (undefined === roomName) {
-            // By default, use the room ID
-            roomName = room_id;
-        }
-
-        return roomName;
-    };
-}]);
+}]);
\ No newline at end of file
diff --git a/webclient/components/matrix/matrix-filter.js b/webclient/components/matrix/matrix-filter.js
new file mode 100644
index 0000000000..0922684e3b
--- /dev/null
+++ b/webclient/components/matrix/matrix-filter.js
@@ -0,0 +1,133 @@
+/*
+ Copyright 2014 OpenMarket Ltd
+ 
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+'use strict';
+
+angular.module('matrixFilter', [])
+
+// Compute the room name according to information we have
+.filter('mRoomName', ['$rootScope', 'matrixService', function($rootScope, matrixService) {
+    return function(room_id) {
+        var roomName;
+
+        // If there is an alias, use it
+        // TODO: only one alias is managed for now
+        var alias = matrixService.getRoomIdToAliasMapping(room_id);
+        if (alias) {
+            roomName = alias;
+        }
+
+        if (undefined === roomName) {
+            // Else, build the name from its users
+            var room = $rootScope.events.rooms[room_id];
+            if (room) {
+                var room_name_event = room["m.room.name"];
+
+                if (room_name_event) {
+                    roomName = room_name_event.content.name;
+                }
+                else if (room.members) {
+                    // Limit the room renaming to 1:1 room
+                    if (2 === Object.keys(room.members).length) {
+                        for (var i in room.members) {
+                            var member = room.members[i];
+                            if (member.state_key !== matrixService.config().user_id) {
+
+                                if (member.state_key in $rootScope.presence) {
+                                    // If the user is available in presence, use the displayname there
+                                    // as it is the most uptodate
+                                    roomName = $rootScope.presence[member.state_key].content.displayname;
+                                }
+                                else if (member.content.displayname) {
+                                    roomName = member.content.displayname;
+                                }
+                                else {
+                                    roomName = member.state_key;
+                                }
+                            }
+                        }
+                    }
+                    else if (1 === Object.keys(room.members).length) {
+                        // The other member may be in the invite list, get all invited users
+                        var invitedUserIDs = [];
+                        for (var i in room.messages) {
+                            var message = room.messages[i];
+                            if ("m.room.member" === message.type && "invite" === message.membership) {
+                                // Make sure there is no duplicate user
+                                if (-1 === invitedUserIDs.indexOf(message.state_key)) {
+                                    invitedUserIDs.push(message.state_key);
+                                }
+                            } 
+                        }
+                        
+                        // For now, only 1:1 room needs to be renamed. It means only 1 invited user
+                        if (1 === invitedUserIDs.length) {
+                            var userID = invitedUserIDs[0];
+
+                            // Try to resolve his displayname in presence global data
+                            if (userID in $rootScope.presence) {
+                                roomName = $rootScope.presence[userID].content.displayname;
+                            }
+                            else {
+                                roomName = userID;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (undefined === roomName) {
+            // By default, use the room ID
+            roomName = room_id;
+        }
+
+        return roomName;
+    };
+}])
+
+// Compute the user display name in a room according to the data already downloaded
+.filter('mUserDisplayName', ['$rootScope', function($rootScope) {
+    return function(user_id, room_id) {
+        var displayName;
+    
+        // Try to find the user name among presence data
+        // Warning: that means we have received before a presence event for this
+        // user which cannot be guaranted.
+        // However, if we get the info by this way, we are sure this is the latest user display name
+        // See FIXME comment below
+        if (user_id in $rootScope.presence) {
+            displayName = $rootScope.presence[user_id].content.displayname;
+        }
+            
+        // FIXME: Would like to use the display name as defined in room members of the room.
+        // But this information is the display name of the user when he has joined the room.
+        // It does not take into account user display name update
+        if (room_id) {
+            var room = $rootScope.events.rooms[room_id];
+            if (room && (user_id in room.members)) {
+                var member = room.members[user_id];
+                displayName = member.content.displayname;
+            }
+        }
+        
+        if (undefined === displayName) {
+            // By default, use the user ID
+            displayName = user_id;
+        }
+        return displayName;
+    };
+}]);
diff --git a/webclient/index.html b/webclient/index.html
index f016dbb877..91b6bf27be 100644
--- a/webclient/index.html
+++ b/webclient/index.html
@@ -29,6 +29,7 @@
     <script src="settings/settings-controller.js"></script>
     <script src="user/user-controller.js"></script>
     <script src="components/matrix/matrix-service.js"></script>
+    <script src="components/matrix/matrix-filter.js"></script>
     <script src="components/matrix/matrix-call.js"></script>
     <script src="components/matrix/matrix-phone-service.js"></script>
     <script src="components/matrix/event-stream-service.js"></script>
diff --git a/webclient/recents/recents-controller.js b/webclient/recents/recents-controller.js
index 3209f2cbdf..0f27f7a660 100644
--- a/webclient/recents/recents-controller.js
+++ b/webclient/recents/recents-controller.js
@@ -16,7 +16,7 @@
 
 'use strict';
 
-angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
+angular.module('RecentsController', ['matrixService', 'matrixFilter', 'eventHandlerService'])
 .controller('RecentsController', ['$scope', 'matrixService', 'eventHandlerService', 
                                function($scope,  matrixService, eventHandlerService) {
     $scope.rooms = {};
@@ -28,13 +28,8 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
     var listenToEventStream = function() {
         // Refresh the list on matrix invitation and message event
         $scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) {
-            var config = matrixService.config();
-            if (isLive && event.state_key === config.user_id && event.content.membership === "invite") {
-                console.log("Invited to room " + event.room_id);
-                // FIXME push membership to top level key to match /im/sync
-                event.membership = event.content.membership;
-
-                $scope.rooms[event.room_id] = event;
+            if (isLive) {
+                $scope.rooms[event.room_id].lastMsg = event;
             }
         });
         $scope.$on(eventHandlerService.MSG_EVENT, function(ngEvent, event, isLive) {
diff --git a/webclient/recents/recents.html b/webclient/recents/recents.html
index 9978e08b13..2e1f897725 100644
--- a/webclient/recents/recents.html
+++ b/webclient/recents/recents.html
@@ -6,7 +6,7 @@
                ng-class="{'recentsRoomSelected': (room.room_id === recentsSelectedRoomID)}">
             <tr>
                 <td class="recentsRoomName">
-                    {{ room.room_id | roomName }}
+                    {{ room.room_id | mRoomName }}
                 </td>
                 <td class="recentsRoomSummaryTS">
                     {{ (room.lastMsg.ts) | date:'MMM d HH:mm' }}
@@ -16,27 +16,38 @@
             <tr>
                 <td colspan="2" class="recentsRoomSummary">
 
-                    <div ng-show="room.membership === 'invite'" >
-                        {{ room.inviter }} invited you
-                    </div>
-
                     <div ng-hide="room.membership === 'invite'" ng-switch="room.lastMsg.type" >
-                         <div ng-switch-when="m.room.member">
-                            {{ room.lastMsg.user_id }}
-                            {{ {"join": "joined", "leave": "left", "invite": "invited", "ban": "banned"}[msg.content.membership] }}
-                            {{ (msg.content.membership === "invite" || msg.content.membership === "ban") ? (msg.state_key || '') : '' }}
+                        <div ng-switch-when="m.room.member">
+                            <span ng-if="'join' === room.lastMsg.content.membership">
+                                {{ room.lastMsg.state_key | mUserDisplayName: room.room_id}} joined
+                            </span>
+                            <span ng-if="'leave' === room.lastMsg.content.membership">
+                                <span ng-if="room.lastMsg.user_id === room.lastMsg.state_key">
+                                    {{room.lastMsg.state_key | mUserDisplayName: room.room_id }} left
+                                </span>
+                                <span ng-if="room.lastMsg.user_id !== room.lastMsg.state_key">
+                                    {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }}
+                                    {{ {"join": "kicked", "ban": "unbanned"}[room.lastMsg.content.prev] }}
+                                    {{ room.lastMsg.state_key | mUserDisplayName: room.room_id }}
+                                </span>
+                            </span>
+                            <span ng-if="'invite' === room.lastMsg.content.membership || 'ban' === room.lastMsg.content.membership">
+                                {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }}
+                                {{ {"invite": "invited", "ban": "banned"}[room.lastMsg.content.membership] }}
+                                {{ room.lastMsg.state_key | mUserDisplayName: room.room_id }}
+                            </span>
                         </div>
 
                         <div ng-switch-when="m.room.message">
                             <div ng-switch="room.lastMsg.content.msgtype">
                                 <div ng-switch-when="m.text">
-                                    {{ room.lastMsg.user_id }} :
+                                    {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} :
                                     <span ng-bind-html="(room.lastMsg.content.body) | linky:'_blank'">
                                     </span>
                                 </div>
 
                                 <div ng-switch-when="m.image">
-                                    {{ room.lastMsg.user_id }} sent an image
+                                    {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} sent an image
                                 </div>
 
                                 <div ng-switch-when="m.emote">
@@ -51,7 +62,7 @@
                         </div>
 
                         <div ng-switch-default>
-                            <div ng-if="room.lastMsg.type.indexOf('m.call.') == 0">
+                            <div ng-if="room.lastMsg.type.indexOf('m.call.') === 0">
                                 Call
                             </div>
                         </div>
diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js
index c3f72c9d25..cdef9ab8a1 100644
--- a/webclient/room/room-controller.js
+++ b/webclient/room/room-controller.js
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-angular.module('RoomController', ['ngSanitize', 'mFileInput'])
+angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput'])
 .controller('RoomController', ['$scope', '$timeout', '$routeParams', '$location', '$rootScope', 'matrixService', 'eventHandlerService', 'mFileUpload', 'mPresence', 'matrixPhoneService', 'MatrixCall',
                                function($scope, $timeout, $routeParams, $location, $rootScope, matrixService, eventHandlerService, mFileUpload, mPresence, matrixPhoneService, MatrixCall) {
    'use strict';
diff --git a/webclient/room/room.html b/webclient/room/room.html
index 6732a7b3ae..493884f601 100644
--- a/webclient/room/room.html
+++ b/webclient/room/room.html
@@ -3,7 +3,7 @@
     <div id="roomHeader">
         <a href ng-click="goToPage('/')"><img src="img/logo-small.png" width="100" height="43" alt="[matrix]"/></a>
         <div id="roomName">
-            {{ room_id  | roomName }}
+            {{ room_id  | mRoomName }}
         </div>
     </div>
 
diff --git a/webclient/settings/settings-controller.js b/webclient/settings/settings-controller.js
index 7a26367a1b..8c877a24e9 100644
--- a/webclient/settings/settings-controller.js
+++ b/webclient/settings/settings-controller.js
@@ -19,6 +19,17 @@ limitations under the License.
 angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInput'])
 .controller('SettingsController', ['$scope', 'matrixService', 'mFileUpload',
                               function($scope, matrixService, mFileUpload) {                 
+    // XXX: duplicated from register
+    var generateClientSecret = function() {
+        var ret = "";
+        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+        for (var i = 0; i < 32; i++) {
+            ret += chars.charAt(Math.floor(Math.random() * chars.length));
+        }
+
+        return ret;
+    };
     $scope.config = matrixService.config();
 
     $scope.profile = {
@@ -106,16 +117,22 @@ angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInpu
     $scope.linkedEmails = {
         linkNewEmail: "", // the email entry box
         emailBeingAuthed: undefined, // to populate verification text
-        authTokenId: undefined, // the token id from the IS
+        authSid: undefined, // the token id from the IS
         emailCode: "", // the code entry box
         linkedEmailList: matrixService.config().emailList // linked email list
     };
     
     $scope.linkEmail = function(email) {
-        matrixService.linkEmail(email).then(
+        if (email != $scope.linkedEmails.emailBeingAuthed) {
+            $scope.linkedEmails.emailBeingAuthed = email;
+            $scope.clientSecret = generateClientSecret();
+            $scope.sendAttempt = 0;
+        }
+        $scope.sendAttempt++;
+        matrixService.linkEmail(email, $scope.clientSecret, $scope.sendAttempt).then(
             function(response) {
                 if (response.data.success === true) {
-                    $scope.linkedEmails.authTokenId = response.data.tokenId;
+                    $scope.linkedEmails.authSid = response.data.sid;
                     $scope.emailFeedback = "You have been sent an email.";
                     $scope.linkedEmails.emailBeingAuthed = email;
                 }
@@ -129,34 +146,44 @@ angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInpu
         );
     };
 
-    $scope.submitEmailCode = function(code) {
-        var tokenId = $scope.linkedEmails.authTokenId;
+    $scope.submitEmailCode = function() {
+        var tokenId = $scope.linkedEmails.authSid;
         if (tokenId === undefined) {
             $scope.emailFeedback = "You have not requested a code with this email.";
             return;
         }
-        matrixService.authEmail(matrixService.config().user_id, tokenId, code).then(
+        matrixService.authEmail($scope.clientSecret, $scope.linkedEmails.authSid, $scope.linkedEmails.emailCode).then(
             function(response) {
-                if ("success" in response.data && response.data.success === false) {
+                if ("errcode" in response.data) {
                     $scope.emailFeedback = "Failed to authenticate email.";
                     return;
                 }
-                var config = matrixService.config();
-                var emailList = {};
-                if ("emailList" in config) {
-                    emailList = config.emailList;
-                }
-                emailList[response.address] = response;
-                // save the new email list
-                config.emailList = emailList;
-                matrixService.setConfig(config);
-                matrixService.saveConfig();
-                // invalidate the email being authed and update UI.
-                $scope.linkedEmails.emailBeingAuthed = undefined;
-                $scope.emailFeedback = "";
-                $scope.linkedEmails.linkedEmailList = emailList;
-                $scope.linkedEmails.linkNewEmail = "";
-                $scope.linkedEmails.emailCode = "";
+                matrixService.bindEmail(matrixService.config().user_id, tokenId, $scope.clientSecret).then(
+                    function(response) {
+                         if ('errcode' in response.data) {
+                             $scope.emailFeedback = "Failed to link email.";
+                             return;
+                         }
+                         var config = matrixService.config();
+                         var emailList = {};
+                         if ("emailList" in config) {
+                             emailList = config.emailList;
+                         }
+                         emailList[$scope.linkedEmails.emailBeingAuthed] = response;
+                         // save the new email list
+                         config.emailList = emailList;
+                         matrixService.setConfig(config);
+                         matrixService.saveConfig();
+                         // invalidate the email being authed and update UI.
+                         $scope.linkedEmails.emailBeingAuthed = undefined;
+                         $scope.emailFeedback = "";
+                         $scope.linkedEmails.linkedEmailList = emailList;
+                         $scope.linkedEmails.linkNewEmail = "";
+                         $scope.linkedEmails.emailCode = "";
+                    }, function(reason) {
+                        $scope.emailFeedback = "Failed to link email: " + reason;
+                    }
+                );
             },
             function(reason) {
                 $scope.emailFeedback = "Failed to auth email: " + reason;
@@ -182,4 +209,4 @@ angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInpu
             $scope.settings.notifications = permission;
         });
     };
-}]);
\ No newline at end of file
+}]);
diff --git a/webclient/settings/settings.html b/webclient/settings/settings.html
index b7fd5dfb50..0af137d0a7 100644
--- a/webclient/settings/settings.html
+++ b/webclient/settings/settings.html
@@ -23,14 +23,14 @@
         </div>
         <br/>
 
-        <h3 style="display: none; ">Linked emails</h3>
-        <div class="section" style="display: none; ">
+        <h3>Linked emails</h3>
+        <div class="section">
             <form>
                 <input size="40" ng-model="linkedEmails.linkNewEmail" ng-enter="linkEmail(linkedEmails.linkNewEmail)" />
                 <button ng-disabled="!linkedEmails.linkNewEmail" ng-click="linkEmail(linkedEmails.linkNewEmail)">
                     Link Email
                 </button>
-                {{ emailFeedback }}    
+                {{ emailFeedback }}
             </form>
             <form ng-hide="!linkedEmails.emailBeingAuthed">
                 Enter validation token for {{ linkedEmails.emailBeingAuthed }}: