From e179ed1f60855d439031113bf52a0ff74c57df95 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 16:16:40 +0100 Subject: [PATCH 1/8] Added generic state/non-state event sending to the API docs. --- docs/client-server/swagger_matrix/rooms | 131 ++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 8 deletions(-) diff --git a/docs/client-server/swagger_matrix/rooms b/docs/client-server/swagger_matrix/rooms index 1ead8b8c1..ce2843d6c 100644 --- a/docs/client-server/swagger_matrix/rooms +++ b/docs/client-server/swagger_matrix/rooms @@ -13,14 +13,104 @@ "token": [] }, "apis": [ + { + "path": "/rooms/{roomId}/send/{eventType}/{txnId}", + "operations": [ + { + "method": "PUT", + "summary": "Send a generic non-state event to this room.", + "notes": "This operation can also be done as a POST to /rooms/{roomId}/send/{eventType}", + "type": "EventId", + "nickname": "send_non_state_event", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "body", + "description": "The event contents", + "required": true, + "type": "EventContent", + "paramType": "body" + }, + { + "name": "roomId", + "description": "The room to send the message in.", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "eventType", + "description": "The type of event to send.", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "txnId", + "description": "A client transaction ID to ensure idempotency. This can only be omitted if the HTTP method becomes a POST.", + "required": true, + "type": "string", + "paramType": "path" + } + ] + } + ] + }, + { + "path": "/rooms/{roomId}/state/{eventType}/{stateKey}", + "operations": [ + { + "method": "PUT", + "summary": "Send a generic state event to this room.", + "notes": "The state key can be omitted, such that you can PUT to /rooms/{roomId}/state/{eventType}. The state key defaults to a 0 length string in this case.", + "type": "void", + "nickname": "send_state_event", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "name": "body", + "description": "The event contents", + "required": true, + "type": "EventContent", + "paramType": "body" + }, + { + "name": "roomId", + "description": "The room to send the message in.", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "eventType", + "description": "The type of event to send.", + "required": true, + "type": "string", + "paramType": "path" + }, + { + "name": "stateKey", + "description": "An identifier used to specify clobbering semantics. State events with the same (roomId, eventType, stateKey) will be replaced.", + "required": true, + "type": "string", + "paramType": "path" + } + ] + } + ] + }, { "path": "/rooms/{roomId}/send/m.room.message/{txnId}", "operations": [ { "method": "PUT", "summary": "Send a message in this room.", - "notes": "Send a message in this room.", - "type": "void", + "notes": "This operation can also be done as a POST to /rooms/{roomId}/send/m.room.message", + "type": "EventId", "nickname": "send_message", "consumes": [ "application/json" @@ -42,7 +132,7 @@ }, { "name": "txnId", - "description": "A client transaction ID to ensure idempotency.", + "description": "A client transaction ID to ensure idempotency. This can only be omitted if the HTTP method becomes a POST.", "required": true, "type": "string", "paramType": "path" @@ -110,8 +200,8 @@ { "method": "PUT", "summary": "Send feedback to a message.", - "notes": "Send feedback to a message.", - "type": "void", + "notes": "This operation can also be done as a POST to /rooms/{roomId}/send/m.room.message.feedback", + "type": "EventId", "nickname": "send_feedback", "consumes": [ "application/json" @@ -133,7 +223,7 @@ }, { "name": "txnId", - "description": "A client transaction ID to ensure idempotency.", + "description": "A client transaction ID to ensure idempotency. This can only be omitted if the HTTP method becomes a POST.", "required": true, "type": "string", "paramType": "path" @@ -633,12 +723,17 @@ "properties": { "event_id": { "type": "string", - "description": "An ID which uniquely identifies this event.", + "description": "An ID which uniquely identifies this event. This is automatically set by the server.", "required": true }, "room_id": { "type": "string", - "description": "The room in which this event occurred.", + "description": "The room in which this event occurred. This is automatically set by the server.", + "required": true + }, + "type": { + "type": "string", + "description": "The event type.", "required": true } }, @@ -646,6 +741,26 @@ "MessageEvent" ] }, + "EventId": { + "id": "EventId", + "properties": { + "event_id": { + "type": "string", + "description": "The allocated event ID for this event.", + "required": true + } + } + }, + "EventContent": { + "id": "EventContent", + "properties": { + "__event_content_keys__": { + "type": "string", + "description": "Event-specific content keys and values.", + "required": false + } + } + }, "MessageEvent": { "id": "MessageEvent", "properties": { From 7ee5288849dc687515f8ad499e7c95c73f842394 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Wed, 27 Aug 2014 16:58:44 +0200 Subject: [PATCH 2/8] Added the recents component at the left hand side of the room page --- webclient/app.css | 9 +++++++++ webclient/room/room.html | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/webclient/app.css b/webclient/app.css index bc23f76f0..e2526dcba 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -387,6 +387,15 @@ h1 { padding-bottom: 5px; } +/*** Recents in the room page ***/ +#roomRecentsTableWrapper { + float: left; + max-width: 320px; + margin-right: 20px; + height: 100%; + overflow-y: auto; +} + /*** Profile ***/ .profile-avatar { diff --git a/webclient/room/room.html b/webclient/room/room.html index c167819f1..236ca0a89 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -7,7 +7,11 @@
{{ room_alias || room_id }}
- + +
+
+
+
From d9155b6a25d706edb85706a1c0cff6dacbdc1640 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Wed, 27 Aug 2014 17:20:41 +0200 Subject: [PATCH 3/8] Highlight the current room in the recents list --- webclient/app.css | 4 ++++ webclient/recents/recents-controller.js | 6 +++++- webclient/recents/recents.html | 5 ++++- webclient/room/room-controller.js | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/webclient/app.css b/webclient/app.css index e2526dcba..8abdd1cb4 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -368,6 +368,10 @@ h1 { background-color: #f8f8ff; } +.recentsRoomSelected { + background-color: #eee; +} + .recentsRoomName { font-size: 16px; padding-top: 7px; diff --git a/webclient/recents/recents-controller.js b/webclient/recents/recents-controller.js index a9805fc38..8f8b08d5b 100644 --- a/webclient/recents/recents-controller.js +++ b/webclient/recents/recents-controller.js @@ -20,7 +20,11 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService']) .controller('RecentsController', ['$scope', 'matrixService', 'eventHandlerService', 'eventStreamService', function($scope, matrixService, eventHandlerService, eventStreamService) { $scope.rooms = {}; - + + // $scope of the parent where the recents component is included can override this value + // in order to highlight a specific room in the list + $scope.recentsSelectedRoomID; + $scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) { var config = matrixService.config(); if (event.state_key === config.user_id && event.content.membership === "invite") { diff --git a/webclient/recents/recents.html b/webclient/recents/recents.html index 6d2864ac9..6fda6c5c6 100644 --- a/webclient/recents/recents.html +++ b/webclient/recents/recents.html @@ -1,6 +1,9 @@
- +
{{ room.room_display_name }} diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index f49deaa48..641ccddce 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -327,6 +327,9 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) var onInit2 = function() { eventHandlerService.reInitRoom($scope.room_id); + // Make recents highlight the current room + $scope.recentsSelectedRoomID = $scope.room_id; + // Join the room matrixService.join($scope.room_id).then( function() { From 4e8d19ee2ba760ac366f89743b873df15d8e1def Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 16:42:33 +0100 Subject: [PATCH 4/8] Added RestServlet for /rooms/$roomid/state --- synapse/rest/room.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 3f2530b14..2d30eeaf3 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -322,6 +322,21 @@ class RoomMessageListRestServlet(RestServlet): defer.returnValue((200, msgs)) +# TODO: Needs unit testing +class RoomStateRestServlet(RestServlet): + PATTERN = client_path_pattern("/rooms/(?P[^/]*)/state$") + + @defer.inlineCallbacks + def on_GET(self, request, room_id): + user = yield self.auth.get_user_by_req(request) + # TODO: Get all the current state for this room and return in the same + # format as initial sync, that is: + # [ + # { state event }, { state event } + # ] + defer.returnValue((200, [])) + + class RoomTriggerBackfill(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/backfill$") @@ -436,3 +451,4 @@ def register_servlets(hs, http_server): RoomMembershipRestServlet(hs).register(http_server) RoomSendEventRestServlet(hs).register(http_server) PublicRoomListRestServlet(hs).register(http_server) + RoomStateRestServlet(hs).register(http_server) From f64887e15c3b554d375e3ae3585aa592ace550dc Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 16:49:01 +0100 Subject: [PATCH 5/8] Added RestServlet for /rooms/$roomid/initialSync --- synapse/rest/room.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 2d30eeaf3..ebe4e2443 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -337,6 +337,35 @@ class RoomStateRestServlet(RestServlet): defer.returnValue((200, [])) +# TODO: Needs unit testing +class RoomInitialSyncRestServlet(RestServlet): + PATTERN = client_path_pattern("/rooms/(?P[^/]*)/initialSync$") + + @defer.inlineCallbacks + def on_GET(self, request, room_id): + user = yield self.auth.get_user_by_req(request) + # TODO: Get all the initial sync data for this room and return in the + # same format as initial sync, that is: + # { + # membership: join, + # messages: [ + # chunk: [ msg events ], + # start: s_tok, + # end: e_tok + # ], + # room_id: foo, + # state: [ + # { state event } , { state event } + # ] + # } + # Probably worth keeping the keys room_id and membership for parity with + # /initialSync even though they must be joined to sync this and know the + # room ID, so clients can reuse the same code (room_id and membership + # are MANDATORY for /initialSync, so the code will expect it to be + # there) + defer.returnValue((200, {})) + + class RoomTriggerBackfill(RestServlet): PATTERN = client_path_pattern("/rooms/(?P[^/]*)/backfill$") @@ -452,3 +481,4 @@ def register_servlets(hs, http_server): RoomSendEventRestServlet(hs).register(http_server) PublicRoomListRestServlet(hs).register(http_server) RoomStateRestServlet(hs).register(http_server) + RoomInitialSyncRestServlet(hs).register(http_server) From 234c50b83480e65d645d4f18912f4b023bdc3954 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Wed, 27 Aug 2014 18:00:08 +0200 Subject: [PATCH 6/8] BF: mFileInput dependency got lost somewhere and upload buttons did not work anymore --- webclient/room/room-controller.js | 2 +- webclient/settings/settings-controller.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 641ccddce..6c98db269 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', 'mUtilities']) +angular.module('RoomController', ['ngSanitize', 'mFileInput', 'mUtilities']) .controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService', 'mFileUpload', 'mUtilities', '$rootScope', function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService, mFileUpload, mUtilities, $rootScope) { 'use strict'; diff --git a/webclient/settings/settings-controller.js b/webclient/settings/settings-controller.js index 5d3f7cb2b..f7d5e8eb7 100644 --- a/webclient/settings/settings-controller.js +++ b/webclient/settings/settings-controller.js @@ -16,7 +16,7 @@ limitations under the License. 'use strict'; -angular.module('SettingsController', ['matrixService', 'mFileUpload']) +angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInput']) .controller('SettingsController', ['$scope', 'matrixService', 'mFileUpload', function($scope, matrixService, mFileUpload) { $scope.config = matrixService.config(); From 6ad9d9c226f8ab9b8a2c4e8059e0a6e995803f16 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 27 Aug 2014 17:02:00 +0100 Subject: [PATCH 7/8] Added /rooms/$roomid/state and /rooms/$roomid/initialSync to API docs. --- docs/client-server/swagger_matrix/rooms | 73 +++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/docs/client-server/swagger_matrix/rooms b/docs/client-server/swagger_matrix/rooms index ce2843d6c..bb49ec5a6 100644 --- a/docs/client-server/swagger_matrix/rooms +++ b/docs/client-server/swagger_matrix/rooms @@ -578,6 +578,51 @@ ] } ] + }, + { + "path": "/rooms/{roomId}/state", + "operations": [ + { + "method": "GET", + "summary": "Get a list of all the current state events for this room.", + "notes": "Get a list of all the current state events for this room.", + "type": "array", + "items": { + "$ref": "Event" + }, + "nickname": "get_state_events", + "parameters": [ + { + "name": "roomId", + "description": "The room to get a list of current state events from.", + "required": true, + "type": "string", + "paramType": "path" + } + ] + } + ] + }, + { + "path": "/rooms/{roomId}/initialSync", + "operations": [ + { + "method": "GET", + "summary": "Get all the current information for this room, including messages and state events.", + "notes": "Get all the current information for this room, including messages and state events.", + "type": "InitialSyncRoomData", + "nickname": "get_room_sync_data", + "parameters": [ + { + "name": "roomId", + "description": "The room to get information for.", + "required": true, + "type": "string", + "paramType": "path" + } + ] + } + ] } ], "models": { @@ -785,6 +830,34 @@ "description": "The fully-qualified user ID." } } + }, + "InitialSyncRoomData": { + "id": "InitialSyncRoomData", + "properties": { + "membership": { + "type": "string", + "description": "This user's membership state in this room.", + "required": true + }, + "room_id": { + "type": "string", + "description": "The ID of this room.", + "required": true + }, + "messages": { + "type": "MessagePaginationChunk", + "description": "The most recent messages for this room, governed by the limit parameter.", + "required": false + }, + "state": { + "type": "array", + "description": "A list of state events representing the current state of the room.", + "required": false, + "items": { + "$ref": "Event" + } + } + } } } } From f53c4300fd3a83b4bb40fc93cad4dbf0e53d1b52 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 27 Aug 2014 17:03:16 +0100 Subject: [PATCH 8/8] improve iOS layout a bit --- webclient/app.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/webclient/app.css b/webclient/app.css index 8abdd1cb4..16f9dd72b 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -7,6 +7,16 @@ .leftBlock { width: 8em ! important; + font-size: 8px ! important; + } + + .rightBlock { + width: 0px ! important; + display: none ! important; + } + + .avatar { + width: 36px ! important; } #header,