From 7346ea85c08d0153644398be8d271169351b0c57 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 4 Sep 2014 11:19:28 +0200 Subject: Moved mRoomName filter into matrix-filter.js, a place for all generic filters using Matrix data. --- webclient/components/matrix/matrix-filter.js | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 webclient/components/matrix/matrix-filter.js (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-filter.js b/webclient/components/matrix/matrix-filter.js new file mode 100644 index 0000000000..a9bdbf66d9 --- /dev/null +++ b/webclient/components/matrix/matrix-filter.js @@ -0,0 +1,100 @@ +/* + 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; + }; +}]); -- cgit 1.4.1 From 3983bae160b63554e657c92450fcb2e1fbaba0c7 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 4 Sep 2014 13:57:27 +0200 Subject: Added mUserDisplayName, a filter to resolve a user display name from a user_id --- webclient/components/matrix/matrix-filter.js | 33 ++++++++++++++++++++++++++++ webclient/recents/recents.html | 18 +++++++-------- 2 files changed, 42 insertions(+), 9 deletions(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-filter.js b/webclient/components/matrix/matrix-filter.js index a9bdbf66d9..0922684e3b 100644 --- a/webclient/components/matrix/matrix-filter.js +++ b/webclient/components/matrix/matrix-filter.js @@ -97,4 +97,37 @@ angular.module('matrixFilter', []) 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/recents/recents.html b/webclient/recents/recents.html index a202473dd4..2e1f897725 100644 --- a/webclient/recents/recents.html +++ b/webclient/recents/recents.html @@ -19,35 +19,35 @@
- {{ room.lastMsg.state_key }} joined + {{ room.lastMsg.state_key | mUserDisplayName: room.room_id}} joined - {{room.lastMsg.state_key }} left + {{room.lastMsg.state_key | mUserDisplayName: room.room_id }} left - {{ room.lastMsg.user_id }} + {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} {{ {"join": "kicked", "ban": "unbanned"}[room.lastMsg.content.prev] }} - {{ room.lastMsg.state_key }} + {{ room.lastMsg.state_key | mUserDisplayName: room.room_id }} - {{ room.lastMsg.user_id }} + {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} {{ {"invite": "invited", "ban": "banned"}[room.lastMsg.content.membership] }} - {{ room.lastMsg.state_key }} + {{ room.lastMsg.state_key | mUserDisplayName: room.room_id }}
- {{ room.lastMsg.user_id }} : + {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} :
- {{ room.lastMsg.user_id }} sent an image + {{ room.lastMsg.user_id | mUserDisplayName: room.room_id }} sent an image
@@ -62,7 +62,7 @@
-
+
Call
-- cgit 1.4.1 From 1bf6c3faad3b072462852821892724da68270090 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 4 Sep 2014 15:10:43 +0200 Subject: BF: presence PUT requests stopped to work with old "state" param yesterday evening :( -https://github.com/matrix-org/synapse/commit/cda31fb7553ba3d880de09a464ae3b62ea6632fc?diff=unified --- webclient/components/matrix/matrix-service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index 7c6d4ae50f..25222a9e9e 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -434,7 +434,7 @@ angular.module('matrixService', []) var path = "/presence/$user_id/status"; path = path.replace("$user_id", config.user_id); return doRequest("PUT", path, undefined, { - state: presence + presence: presence }); }, -- cgit 1.4.1 From 3bc7bba2625e291fcbf0c30f30c20fc2d1756a49 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 4 Sep 2014 09:40:15 -0700 Subject: switch IRC-style command parser to use regexps rather than split(" ") so that it doesn't choke on consecutive whitespaces yield better errors for invalid commands don't pass invalid commands through as messages support kick reasons --- webclient/components/matrix/matrix-service.js | 11 +- webclient/room/room-controller.js | 140 ++++++++++++++++---------- 2 files changed, 96 insertions(+), 55 deletions(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index 25222a9e9e..436ff5462a 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -169,14 +169,19 @@ angular.module('matrixService', []) // Change the membership of an another user setMembership: function(room_id, user_id, membershipValue) { + return this.setMemberShipObject(room_id, user_id, { + membership : membershipValue + }); + }, + + // Change the membership of an another user + setMembershipObject: function(room_id, user_id, membershipObject) { // The REST path spec var path = "/rooms/$room_id/state/m.room.member/$user_id"; path = path.replace("$room_id", encodeURIComponent(room_id)); path = path.replace("$user_id", user_id); - return doRequest("PUT", path, undefined, { - membership: membershipValue - }); + return doRequest("PUT", path, undefined, membershipObject); }, // Bans a user from from a room diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index cdef9ab8a1..6e6d6e6356 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -287,94 +287,130 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) $scope.state.sending = true; var promise; + var isCmd = false; // Check for IRC style commands first - if ($scope.textInput.indexOf("/") === 0) { - var args = $scope.textInput.split(' '); - var cmd = args[0]; + var line = $scope.textInput; + + // trim any trailing whitespace, as it can confuse the parser for IRC-style commands + line = line.replace(/\s+$/, ""); + + if (line[0] === "/" && line[1] !== "/") { + isCmd = true; + + var bits = line.match(/^(\S+?)( +(.*))?$/); + var cmd = bits[1]; + var args = bits[3]; + + console.log("cmd: " + cmd + ", args: " + args); switch (cmd) { case "/me": - var emoteMsg = args.slice(1).join(' '); - promise = matrixService.sendEmoteMessage($scope.room_id, emoteMsg); + promise = matrixService.sendEmoteMessage($scope.room_id, args); break; case "/nick": // Change user display name - if (2 === args.length) { - promise = matrixService.setDisplayName(args[1]); - } + promise = matrixService.setDisplayName(args); break; case "/kick": - // Kick a user from the room - if (2 === args.length) { - var user_id = args[1]; - - // Set his state in the room as leave - promise = matrixService.setMembership($scope.room_id, user_id, "leave"); + var matches = args.match(/^(\S+?)( +(.*))?$/); + if (matches.length === 2) { + promise = matrixService.setMembership($scope.room_id, matches[1], "leave"); + } + else if (matches.length === 4) { + promise = matrixService.setMembershipObject($scope.room_id, matches[1], { + membership: "leave", + reason: matches[3] // TODO: we need to specify resaon in the spec + }); + } + else { + $scope.feedback = "Usage: /kick []"; } break; - + case "/ban": - // Ban a user from the room - if (2 <= args.length) { - // TODO: The user may have entered the display name - // Need display name -> user_id resolution. Pb: how to manage user with same display names? - var user_id = args[1]; - - // Does the user provide a reason? - if (3 <= args.length) { - var reason = args.slice(2).join(' '); - } - promise = matrixService.ban($scope.room_id, user_id, reason); + // Ban a user from the room with optional reason + var matches = args.match(/^(\S+?)( +(.*))?$/); + if (matches) { + promise = matrixService.ban($scope.room_id, matches[1], matches[3]); + } + else { + $scope.feedback = "Usage: /ban []"; } break; - + case "/unban": // Unban a user from the room - if (2 === args.length) { - var user_id = args[1]; - - // Reset the user membership to leave to unban him - promise = matrixService.setMembership($scope.room_id, user_id, "leave"); + // FIXME: this feels horribly asymmetrical - why are we banning via RPC + // and unbanning by editing the membership list? + // Why can't we specify a reason? + var matches = args.match(/^(\S+)$/); + if (matches) { + // Reset the user membership to "leave" to unban him + promise = matrixService.setMembership($scope.room_id, args, "leave"); + } + else { + $scope.feedback = "Usage: /unban "; } break; case "/op": // Define the power level of a user - if (3 === args.length) { - var user_id = args[1]; - var powerLevel = parseInt(args[2]); - promise = matrixService.setUserPowerLevel($scope.room_id, user_id, powerLevel); + var matches = args.match(/^(\S+?)( +(\d+))?$/); + var powerLevel = 50; // default power level for op + if (matches) { + var user_id = matches[1]; + if (matches.length == 4) { + powerLevel = parseInt(matches[3]); + } + if (powerLevel !== NaN) { + promise = matrixService.setUserPowerLevel($scope.room_id, user_id, powerLevel); + } + } + if (!promise) { + $scope.feedback = "Usage: /op []"; } break; case "/deop": // Reset the power level of a user - if (2 === args.length) { - var user_id = args[1]; - promise = matrixService.setUserPowerLevel($scope.room_id, user_id, undefined); + var matches = args.match(/^(\S+)$/); + if (matches) { + promise = matrixService.setUserPowerLevel($scope.room_id, args, undefined); + } + else { + $scope.feedback = "Usage: /deop "; } break; + + default: + $scope.feedback = ("Unrecognised IRC-style command: " + cmd); + break; } } - if (!promise) { - // Send the text message + // By default send this as a message unless it's an IRC-style command + if (!promise && !isCmd) { promise = matrixService.sendTextMessage($scope.room_id, $scope.textInput); } - - promise.then( - function() { - console.log("Request successfully sent"); - $scope.textInput = ""; - $scope.state.sending = false; - }, - function(error) { - $scope.feedback = "Request failed: " + error.data.error; - $scope.state.sending = false; - }); + + if (promise) { + promise.then( + function() { + console.log("Request successfully sent"); + $scope.textInput = ""; + $scope.state.sending = false; + }, + function(error) { + $scope.feedback = "Request failed: " + error.data.error; + $scope.state.sending = false; + }); + } + else { + $scope.state.sending = false; + } }; $scope.onInit = function() { -- cgit 1.4.1 From f286a4fcd46ff6c2c42a8732d004d8188aaa65f8 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 5 Sep 2014 15:50:44 +0200 Subject: Fixed empty display name (content.displayname in a room member can be null) --- webclient/components/matrix/event-handler-service.js | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'webclient/components') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index ee478d2eb0..79d352a7c4 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -26,6 +26,9 @@ Typically, this service will store events or broadcast them to any listeners (e.g. controllers) via $broadcast. Alternatively, it may update the $rootScope if typically all the $on method would do is update its own $scope. */ + +var toto; + angular.module('eventHandlerService', []) .factory('eventHandlerService', ['matrixService', '$rootScope', '$q', function(matrixService, $rootScope, $q) { var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT"; @@ -38,6 +41,9 @@ angular.module('eventHandlerService', []) var InitialSyncDeferred = $q.defer(); + + toto = $rootScope; + $rootScope.events = { rooms: {} // will contain roomId: { messages:[], members:{userid1: event} } }; -- cgit 1.4.1 From ec1cc29ecbc03e968789d799fbc2054468a36147 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 5 Sep 2014 15:51:34 +0200 Subject: Revert "Fixed empty display name (content.displayname in a room member can be null)" This reverts commit f286a4fcd46ff6c2c42a8732d004d8188aaa65f8. --- webclient/components/matrix/event-handler-service.js | 6 ------ 1 file changed, 6 deletions(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 79d352a7c4..ee478d2eb0 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -26,9 +26,6 @@ Typically, this service will store events or broadcast them to any listeners (e.g. controllers) via $broadcast. Alternatively, it may update the $rootScope if typically all the $on method would do is update its own $scope. */ - -var toto; - angular.module('eventHandlerService', []) .factory('eventHandlerService', ['matrixService', '$rootScope', '$q', function(matrixService, $rootScope, $q) { var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT"; @@ -41,9 +38,6 @@ angular.module('eventHandlerService', []) var InitialSyncDeferred = $q.defer(); - - toto = $rootScope; - $rootScope.events = { rooms: {} // will contain roomId: { messages:[], members:{userid1: event} } }; -- cgit 1.4.1 From 4b7a5b7bfa792d91775821208aaef3be77e3163b Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 5 Sep 2014 15:54:34 +0200 Subject: Fixed empty display name (content.displayname in a room member can be null) --- webclient/components/matrix/matrix-filter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-filter.js b/webclient/components/matrix/matrix-filter.js index 0922684e3b..260e0827df 100644 --- a/webclient/components/matrix/matrix-filter.js +++ b/webclient/components/matrix/matrix-filter.js @@ -120,7 +120,9 @@ angular.module('matrixFilter', []) 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 (member.content.displayname) { + displayName = member.content.displayname; + } } } -- cgit 1.4.1 From 35014788282f43ba8a6d6da414dced5694027256 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 5 Sep 2014 16:56:50 +0200 Subject: BF: Make /unban work again --- webclient/components/matrix/matrix-service.js | 2 +- webclient/room/room-controller.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index 436ff5462a..18a4841298 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -169,7 +169,7 @@ angular.module('matrixService', []) // Change the membership of an another user setMembership: function(room_id, user_id, membershipValue) { - return this.setMemberShipObject(room_id, user_id, { + return this.setMembershipObject(room_id, user_id, { membership : membershipValue }); }, diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index b9ba23dc48..5a2f06d8ee 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -351,7 +351,7 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) var matches = args.match(/^(\S+)$/); if (matches) { // Reset the user membership to "leave" to unban him - promise = matrixService.setMembership($scope.room_id, args, "leave"); + promise = matrixService.setMembership($scope.room_id, matches[1], "leave"); } else { $scope.feedback = "Usage: /unban "; -- cgit 1.4.1 From 3be615677407a4224202a3ae107762b1f3bc97ac Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 5 Sep 2014 17:30:50 +0200 Subject: Created kick & unban methods in matrixService. Made some factorisation. --- webclient/components/matrix/matrix-service.js | 32 ++++++++++++++++++--------- webclient/room/room-controller.js | 15 +++---------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'webclient/components') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index 18a4841298..8a0223979c 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -168,23 +168,20 @@ angular.module('matrixService', []) }, // Change the membership of an another user - setMembership: function(room_id, user_id, membershipValue) { - return this.setMembershipObject(room_id, user_id, { - membership : membershipValue - }); - }, - - // Change the membership of an another user - setMembershipObject: function(room_id, user_id, membershipObject) { + setMembership: function(room_id, user_id, membershipValue, reason) { + // The REST path spec var path = "/rooms/$room_id/state/m.room.member/$user_id"; path = path.replace("$room_id", encodeURIComponent(room_id)); path = path.replace("$user_id", user_id); - return doRequest("PUT", path, undefined, membershipObject); + return doRequest("PUT", path, undefined, { + membership : membershipValue, + reason: reason + }); }, - // Bans a user from from a room + // Bans a user from a room ban: function(room_id, user_id, reason) { var path = "/rooms/$room_id/ban"; path = path.replace("$room_id", encodeURIComponent(room_id)); @@ -194,7 +191,20 @@ angular.module('matrixService', []) reason: reason }); }, - + + // Unbans a user in a room + unban: function(room_id, user_id) { + // FIXME: To update when there will be homeserver API for unban + // For now, do an unban by resetting the user membership to "leave" + return this.setMembership(room_id, user_id, "leave"); + }, + + // Kicks a user from a room + kick: function(room_id, user_id, reason) { + // Set the user membership to "leave" to kick him + return this.setMembership(room_id, user_id, "leave", reason); + }, + // Retrieves the room ID corresponding to a room alias resolveRoomAlias:function(room_alias) { var path = "/_matrix/client/api/v1/directory/room/$room_alias"; diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 39f8635d76..905a0723d8 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -325,15 +325,9 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) // Kick a user from the room with an optional reason if (args) { var matches = args.match(/^(\S+?)( +(.*))?$/); - if (matches.length === 2) { - promise = matrixService.setMembership($scope.room_id, matches[1], "leave"); + if (matches) { + promise = matrixService.kick($scope.room_id, matches[1], matches[3]); } - else if (matches.length === 4) { - promise = matrixService.setMembershipObject($scope.room_id, matches[1], { - membership: "leave", - reason: matches[3] // TODO: we need to specify resaon in the spec - }); - } } if (!promise) { @@ -357,14 +351,11 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) case "/unban": // Unban a user from the room - // FIXME: this feels horribly asymmetrical - why are we banning via RPC - // and unbanning by editing the membership list? - // Why can't we specify a reason? if (args) { var matches = args.match(/^(\S+)$/); if (matches) { // Reset the user membership to "leave" to unban him - promise = matrixService.setMembership($scope.room_id, matches[1], "leave"); + promise = matrixService.unban($scope.room_id, matches[1]); } } -- cgit 1.4.1