Merge branch 'master' of github.com:matrix-org/synapse into sql_refactor

Conflicts:
	tests/rest/test_presence.py
	tests/rest/test_rooms.py
	tests/utils.py
This commit is contained in:
Erik Johnston 2014-08-19 14:48:19 +01:00
commit 347242a5c4
29 changed files with 1258 additions and 393 deletions

View file

@ -89,6 +89,7 @@ h1 {
height: 100px;
position: relative;
background-color: #000;
cursor: pointer;
}
.userAvatar .userAvatarImage {
@ -251,6 +252,7 @@ h1 {
height: 160px;
display:table-cell;
vertical-align: middle;
text-align: center;
}
.profile-avatar img {
@ -258,6 +260,14 @@ h1 {
max-height: 100%;
}
/*** User profile page ***/
#user-ids {
padding-left: 1em;
}
#user-displayname {
font-size: 16pt;
}
/******************************/
#header {

View file

@ -20,6 +20,7 @@ var matrixWebClient = angular.module('matrixWebClient', [
'LoginController',
'RoomController',
'RoomsController',
'UserController',
'matrixService',
'eventStreamService',
'eventHandlerService',
@ -33,7 +34,13 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
templateUrl: 'login/login.html',
controller: 'LoginController'
}).
when('/room/:room_id', {
when('/room/:room_id_or_alias', {
templateUrl: 'room/room.html',
controller: 'RoomController'
}).
when('/room/', { // room URL with room alias in it (ex: http://127.0.0.1:8000/#/room/#public:localhost:8080) will come here.
// The reason is that 2nd hash key breaks routeProvider parameters cutting so that the URL will not match with
// the previous '/room/:room_id_or_alias' URL rule
templateUrl: 'room/room.html',
controller: 'RoomController'
}).
@ -41,6 +48,10 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
templateUrl: 'rooms/rooms.html',
controller: 'RoomsController'
}).
when('/user/:user_matrix_id', {
templateUrl: 'user/user.html',
controller: 'UserController'
}).
otherwise({
redirectTo: '/rooms'
});

View file

@ -29,7 +29,7 @@ angular.module('mFileInput', [])
scope: {
selectedFile: '=mFileInput'
},
link: function(scope, element, attrs, ctrl) {
element.bind("click", function() {
element.find("input")[0].click();
@ -38,6 +38,9 @@ angular.module('mFileInput', [])
scope.$apply();
});
});
// Change the mouse icon on mouseover on this element
element.css("cursor", "pointer");
}
};
});

View file

@ -16,11 +16,12 @@
'use strict';
// TODO determine if this is really required as a separate service to matrixService.
/*
* Upload an HTML5 file to a server
*/
angular.module('mFileUpload', [])
.service('mFileUpload', ['$http', '$q', function ($http, $q) {
.service('mFileUpload', ['matrixService', '$q', function (matrixService, $q) {
/*
* Upload an HTML5 file to a server and returned a promise
@ -28,20 +29,19 @@ angular.module('mFileUpload', [])
*/
this.uploadFile = function(file) {
var deferred = $q.defer();
// @TODO: This service runs with the do_POST hacky implementation of /synapse/demos/webserver.py.
// This is temporary until we have a true file upload service
console.log("Uploading " + file.name + "...");
$http.post(file.name, file)
.success(function(data, status, headers, config) {
deferred.resolve(location.origin + data.url);
console.log(" -> Successfully uploaded! Available at " + location.origin + data.url);
}).
error(function(data, status, headers, config) {
console.log(" -> Failed to upload" + file.name);
deferred.reject();
});
console.log("Uploading " + file.name + "... to /matrix/content");
matrixService.uploadContent(file).then(
function(response) {
var content_url = location.origin + "/matrix/content/" + response.data.content_token;
console.log(" -> Successfully uploaded! Available at " + content_url);
deferred.resolve(content_url);
},
function(error) {
console.log(" -> Failed to upload " + file.name);
deferred.reject(error);
}
);
return deferred.promise;
};
}]);
}]);

View file

@ -54,13 +54,14 @@ angular.module('matrixService', [])
params.access_token = config.access_token;
if (path.indexOf(prefixPath) !== 0) {
path = prefixPath + path;
}
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
};
var doBaseRequest = function(baseUrl, method, path, params, data, headers) {
if (path.indexOf(prefixPath) !== 0) {
path = prefixPath + path;
}
return $http({
method: method,
url: baseUrl + path,
@ -165,6 +166,16 @@ angular.module('matrixService', [])
return doRequest("DELETE", path, undefined, undefined);
},
// Retrieves the room ID corresponding to a room alias
resolveRoomAlias:function(room_alias) {
var path = "/matrix/client/api/v1/ds/room/$room_alias";
room_alias = encodeURIComponent(room_alias);
path = path.replace("$room_alias", room_alias);
return doRequest("GET", path, undefined, {});
},
sendMessage: function(room_id, msg_id, content) {
// The REST path spec
var path = "/rooms/$room_id/messages/$from/$msg_id";
@ -309,6 +320,17 @@ angular.module('matrixService', [])
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
},
uploadContent: function(file) {
var path = "/matrix/content";
var headers = {
"Content-Type": undefined // undefined means angular will figure it out
};
var params = {
access_token: config.access_token
};
return doBaseRequest(config.homeserver, "POST", path, params, file, headers);
},
// start listening on /events
getEventStream: function(from, timeout) {
var path = "/events";

View file

@ -16,6 +16,7 @@
<script src="login/login-controller.js"></script>
<script src="room/room-controller.js"></script>
<script src="rooms/rooms-controller.js"></script>
<script src="user/user-controller.js"></script>
<script src="components/matrix/matrix-service.js"></script>
<script src="components/matrix/event-stream-service.js"></script>
<script src="components/matrix/event-handler-service.js"></script>

View file

@ -108,8 +108,11 @@ angular.module('RoomController', ['ngSanitize'])
function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService) {
'use strict';
var MESSAGES_PER_PAGINATION = 30;
$scope.room_id = $routeParams.room_id;
$scope.room_alias = matrixService.getRoomIdToAliasMapping($scope.room_id);
// Room ids. Computed and resolved in onInit
$scope.room_id = undefined;
$scope.room_alias = undefined;
$scope.state = {
user_id: matrixService.config().user_id,
events_from: "END", // when to start the event stream from.
@ -144,7 +147,7 @@ angular.module('RoomController', ['ngSanitize'])
if (document.hidden) {
var notification = new window.Notification(
($scope.members[event.user_id].displayname || event.user_id) +
" (" + $scope.room_alias + ")",
" (" + ($scope.room_alias || $scope.room_id) + ")", // FIXME: don't leak room_ids here
{
"body": event.content.body,
"icon": $scope.members[event.user_id].avatar_url,
@ -342,7 +345,57 @@ angular.module('RoomController', ['ngSanitize'])
$scope.onInit = function() {
// $timeout(function() { document.getElementById('textInput').focus() }, 0);
console.log("onInit");
// Does the room ID provided in the URL?
var room_id_or_alias;
if ($routeParams.room_id_or_alias) {
room_id_or_alias = decodeURIComponent($routeParams.room_id_or_alias);
}
if (room_id_or_alias && '!' === room_id_or_alias[0]) {
// Yes. We can start right now
$scope.room_id = room_id_or_alias;
$scope.room_alias = matrixService.getRoomIdToAliasMapping($scope.room_id);
onInit2();
}
else {
// No. The URL contains the room alias. Get this alias.
if (room_id_or_alias) {
// The room alias was passed urlencoded, use it as is
$scope.room_alias = room_id_or_alias;
}
else {
// Else get the room alias by hand from the URL
// ie: extract #public:localhost:8080 from http://127.0.0.1:8000/#/room/#public:localhost:8080
if (3 === location.hash.split("#").length) {
$scope.room_alias = "#" + location.hash.split("#")[2];
}
else {
// In case of issue, go to the default page
console.log("Error: cannot extract room alias");
$location.path("/");
return;
}
}
// Need a room ID required in Matrix API requests
console.log("Resolving alias: " + $scope.room_alias);
matrixService.resolveRoomAlias($scope.room_alias).then(function(response) {
$scope.room_id = response.data.room_id;
console.log(" -> Room ID: " + $scope.room_id);
// Now, we can start
onInit2();
},
function () {
// In case of issue, go to the default page
console.log("Error: cannot resolve room alias");
$location.path("/");
});
}
};
var onInit2 = function() {
// Join the room
matrixService.join($scope.room_id).then(
function() {
@ -380,6 +433,11 @@ angular.module('RoomController', ['ngSanitize'])
});
};
// Open the user profile page
$scope.goToUserPage = function(user_id) {
$location.url("/user/" + user_id);
};
$scope.leaveRoom = function() {
matrixService.leave($scope.room_id).then(

View file

@ -10,9 +10,13 @@
<div id="usersTableWrapper">
<table id="usersTable">
<tr ng-repeat="member in members | orderMembersList">
<td class="userAvatar">
<img class="userAvatarImage" ng-src="{{member.avatar_url || 'img/default-profile.jpg'}}" width="80" height="80"/>
<img class="userAvatarGradient" src="img/gradient.png" width="80" height="24"/>
<td class="userAvatar" ng-click="goToUserPage(member.id)">
<img class="userAvatarImage"
ng-src="{{member.avatar_url || 'img/default-profile.jpg'}}"
alt="{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}"
title="{{ member.id }}"
width="80" height="80"/>
<img class="userAvatarGradient" src="img/gradient.png" title="{{ member.id }}" width="80" height="24"/>
<div class="userName">{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}<br/>{{ member.displayname ? "" : member.id.substr(member.id.indexOf(':')) }}</div>
</td>
<td class="userPresence" ng-class="member.presenceState === 'online' ? 'online' : (member.presenceState === 'unavailable' ? 'unavailable' : '')">

View file

@ -149,12 +149,8 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload',
$scope.joinAlias = function(room_alias) {
matrixService.joinAlias(room_alias).then(
function(response) {
if (response.data.hasOwnProperty("room_id")) {
$location.path("room/" + response.data.room_id);
return;
} else {
// TODO (erikj): Do something here?
}
// Go to this room
$location.path("room/" + room_alias);
},
function(error) {
$scope.feedback = "Can't join room: " + error.data;

View file

@ -65,7 +65,7 @@
<div class="rooms" ng-repeat="(rm_id, room) in rooms">
<div>
<a href="#/room/{{ rm_id }}" >{{ room.room_alias }}</a> {{room.membership === 'invite' ? ' (invited)' : ''}}
<a href="#/room/{{ room.room_alias ? room.room_alias : rm_id }}" >{{ room.room_alias }}</a> {{room.membership === 'invite' ? ' (invited)' : ''}}
</div>
</div>
<br/>
@ -74,7 +74,7 @@
<div class="public_rooms" ng-repeat="room in public_rooms">
<div>
<a href="#/room/{{ room.room_id }}" >{{ room.room_alias }}</a>
<a href="#/room/{{ room.room_alias ? room.room_alias : room.room_id }}" >{{ room.room_alias }}</a>
</div>
</div>
<br/>

View file

@ -0,0 +1,38 @@
/*
Copyright 2014 matrix.org
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('UserController', ['matrixService'])
.controller('UserController', ['$scope', '$routeParams', 'matrixService',
function($scope, $routeParams, matrixService) {
$scope.user = {
id: $routeParams.user_matrix_id,
displayname: "",
avatar_url: undefined
};
matrixService.getDisplayName($scope.user.id).then(
function(response) {
$scope.user.displayname = response.data.displayname;
}
);
matrixService.getProfilePictureUrl($scope.user.id).then(
function(response) {
$scope.user.avatar_url = response.data.avatar_url;
}
);
}]);

30
webclient/user/user.html Normal file
View file

@ -0,0 +1,30 @@
<div ng-controller="UserController" class="user">
<div id="page">
<div id="wrapper">
<div>
<form>
<table>
<tr>
<td>
<div class="profile-avatar">
<img ng-src="{{ user.avatar_url || 'img/default-profile.jpg' }}"/>
</div>
</td>
<td>
<div id="user-ids">
<div id="user-displayname">{{ user.displayname }}</div>
<div>{{ user.id }}</div>
</div>
</td>
</tr>
</table>
</form>
</div>
{{ feedback }}
</div>
</div>
</div>