mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-12-27 03:49:25 -05:00
Merge branch 'develop' of github.com:matrix-org/synapse into federation_authorization
This commit is contained in:
commit
7a07263281
16
CHANGES.rst
16
CHANGES.rst
@ -1,3 +1,19 @@
|
|||||||
|
Changes in synapse 0.4.2 (2014-10-31)
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Homeserver:
|
||||||
|
* Fix bugs where we did not notify users of correct presence updates.
|
||||||
|
* Fix bug where we did not handle sub second event stream timeouts.
|
||||||
|
|
||||||
|
Webclient:
|
||||||
|
* Add ability to click on messages to see JSON.
|
||||||
|
* Add ability to redact messages.
|
||||||
|
* Add ability to view and edit all room state JSON.
|
||||||
|
* Handle incoming redactions.
|
||||||
|
* Improve feedback on errors.
|
||||||
|
* Fix bugs in mobile CSS.
|
||||||
|
* Fix bugs with desktop notifications.
|
||||||
|
|
||||||
Changes in synapse 0.4.1 (2014-10-17)
|
Changes in synapse 0.4.1 (2014-10-17)
|
||||||
=====================================
|
=====================================
|
||||||
Webclient:
|
Webclient:
|
||||||
|
@ -16,4 +16,4 @@
|
|||||||
""" This is a reference implementation of a synapse home server.
|
""" This is a reference implementation of a synapse home server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.4.1"
|
__version__ = "0.4.2"
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
"""Contains functions for registering clients."""
|
"""Contains functions for registering clients."""
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
from twisted.python import log
|
|
||||||
|
|
||||||
from synapse.types import UserID
|
from synapse.types import UserID
|
||||||
from synapse.api.errors import (
|
from synapse.api.errors import (
|
||||||
@ -129,7 +128,7 @@ class RegistrationHandler(BaseHandler):
|
|||||||
try:
|
try:
|
||||||
threepid = yield self._threepid_from_creds(c)
|
threepid = yield self._threepid_from_creds(c)
|
||||||
except:
|
except:
|
||||||
log.err()
|
logger.exception("Couldn't validate 3pid")
|
||||||
raise RegistrationError(400, "Couldn't validate 3pid")
|
raise RegistrationError(400, "Couldn't validate 3pid")
|
||||||
|
|
||||||
if not threepid:
|
if not threepid:
|
||||||
|
@ -30,6 +30,7 @@ var matrixWebClient = angular.module('matrixWebClient', [
|
|||||||
'MatrixCall',
|
'MatrixCall',
|
||||||
'eventStreamService',
|
'eventStreamService',
|
||||||
'eventHandlerService',
|
'eventHandlerService',
|
||||||
|
'notificationService',
|
||||||
'infinite-scroll',
|
'infinite-scroll',
|
||||||
'ui.bootstrap',
|
'ui.bootstrap',
|
||||||
'monospaced.elastic'
|
'monospaced.elastic'
|
||||||
|
@ -27,8 +27,8 @@ Typically, this service will store events or broadcast them to any listeners
|
|||||||
if typically all the $on method would do is update its own $scope.
|
if typically all the $on method would do is update its own $scope.
|
||||||
*/
|
*/
|
||||||
angular.module('eventHandlerService', [])
|
angular.module('eventHandlerService', [])
|
||||||
.factory('eventHandlerService', ['matrixService', '$rootScope', '$q', '$timeout', 'mPresence',
|
.factory('eventHandlerService', ['matrixService', '$rootScope', '$q', '$timeout', 'mPresence', 'notificationService',
|
||||||
function(matrixService, $rootScope, $q, $timeout, mPresence) {
|
function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService) {
|
||||||
var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT";
|
var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT";
|
||||||
var MSG_EVENT = "MSG_EVENT";
|
var MSG_EVENT = "MSG_EVENT";
|
||||||
var MEMBER_EVENT = "MEMBER_EVENT";
|
var MEMBER_EVENT = "MEMBER_EVENT";
|
||||||
@ -46,71 +46,6 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
|
|||||||
|
|
||||||
$rootScope.presence = {};
|
$rootScope.presence = {};
|
||||||
|
|
||||||
// TODO: This is attached to the rootScope so .html can just go containsBingWord
|
|
||||||
// for determining classes so it is easy to highlight bing messages. It seems a
|
|
||||||
// bit strange to put the impl in this service though, but I can't think of a better
|
|
||||||
// file to put it in.
|
|
||||||
$rootScope.containsBingWord = function(content) {
|
|
||||||
if (!content || $.type(content) != "string") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var bingWords = matrixService.config().bingWords;
|
|
||||||
var shouldBing = false;
|
|
||||||
|
|
||||||
// case-insensitive name check for user_id OR display_name if they exist
|
|
||||||
var userRegex = "";
|
|
||||||
var myUserId = matrixService.config().user_id;
|
|
||||||
if (myUserId) {
|
|
||||||
var localpart = getLocalPartFromUserId(myUserId);
|
|
||||||
if (localpart) {
|
|
||||||
localpart = localpart.toLocaleLowerCase();
|
|
||||||
userRegex += "\\b" + localpart + "\\b";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var myDisplayName = matrixService.config().display_name;
|
|
||||||
if (myDisplayName) {
|
|
||||||
myDisplayName = myDisplayName.toLocaleLowerCase();
|
|
||||||
if (userRegex.length > 0) {
|
|
||||||
userRegex += "|";
|
|
||||||
}
|
|
||||||
userRegex += "\\b" + myDisplayName + "\\b";
|
|
||||||
}
|
|
||||||
|
|
||||||
var r = new RegExp(userRegex, 'i');
|
|
||||||
if (content.search(r) >= 0) {
|
|
||||||
shouldBing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (myDisplayName && content.toLocaleLowerCase().indexOf(myDisplayName) != -1) ||
|
|
||||||
(myUserId && content.toLocaleLowerCase().indexOf(myUserId) != -1) ) {
|
|
||||||
shouldBing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bing word list check
|
|
||||||
if (bingWords && !shouldBing) {
|
|
||||||
for (var i=0; i<bingWords.length; i++) {
|
|
||||||
var re = RegExp(bingWords[i]);
|
|
||||||
if (content.search(re) != -1) {
|
|
||||||
shouldBing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shouldBing;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getLocalPartFromUserId = function(user_id) {
|
|
||||||
if (!user_id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var localpartRegex = /@(.*):\w+/i
|
|
||||||
var results = localpartRegex.exec(user_id);
|
|
||||||
if (results && results.length == 2) {
|
|
||||||
return results[1];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
var initialSyncDeferred;
|
var initialSyncDeferred;
|
||||||
|
|
||||||
var reset = function() {
|
var reset = function() {
|
||||||
@ -228,7 +163,12 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (window.Notification && event.user_id != matrixService.config().user_id) {
|
if (window.Notification && event.user_id != matrixService.config().user_id) {
|
||||||
var shouldBing = $rootScope.containsBingWord(event.content.body);
|
var shouldBing = notificationService.containsBingWord(
|
||||||
|
matrixService.config().user_id,
|
||||||
|
matrixService.config().display_name,
|
||||||
|
matrixService.config().bingWords,
|
||||||
|
event.content.body
|
||||||
|
);
|
||||||
|
|
||||||
// Ideally we would notify only when the window is hidden (i.e. document.hidden = true).
|
// Ideally we would notify only when the window is hidden (i.e. document.hidden = true).
|
||||||
//
|
//
|
||||||
@ -258,6 +198,9 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
|
|||||||
if (event.content.msgtype === "m.emote") {
|
if (event.content.msgtype === "m.emote") {
|
||||||
message = "* " + displayname + " " + message;
|
message = "* " + displayname + " " + message;
|
||||||
}
|
}
|
||||||
|
else if (event.content.msgtype === "m.image") {
|
||||||
|
message = displayname + " sent an image.";
|
||||||
|
}
|
||||||
|
|
||||||
var roomTitle = matrixService.getRoomIdToAliasMapping(event.room_id);
|
var roomTitle = matrixService.getRoomIdToAliasMapping(event.room_id);
|
||||||
var theRoom = $rootScope.events.rooms[event.room_id];
|
var theRoom = $rootScope.events.rooms[event.room_id];
|
||||||
@ -269,22 +212,15 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) {
|
|||||||
roomTitle = event.room_id;
|
roomTitle = event.room_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var notification = new window.Notification(
|
notificationService.showNotification(
|
||||||
displayname +
|
displayname + " (" + roomTitle + ")",
|
||||||
" (" + roomTitle + ")",
|
message,
|
||||||
{
|
member ? member.avatar_url : undefined,
|
||||||
"body": message,
|
function() {
|
||||||
"icon": member ? member.avatar_url : undefined
|
console.log("notification.onclick() room=" + event.room_id);
|
||||||
});
|
$rootScope.goToPage('room/' + event.room_id);
|
||||||
|
}
|
||||||
notification.onclick = function() {
|
);
|
||||||
console.log("notification.onclick() room=" + event.room_id);
|
|
||||||
$rootScope.goToPage('room/' + (event.room_id));
|
|
||||||
};
|
|
||||||
|
|
||||||
$timeout(function() {
|
|
||||||
notification.close();
|
|
||||||
}, 5 * 1000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
104
webclient/components/matrix/notification-service.js
Normal file
104
webclient/components/matrix/notification-service.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
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';
|
||||||
|
|
||||||
|
/*
|
||||||
|
This service manages notifications: enabling, creating and showing them. This
|
||||||
|
also contains 'bing word' logic.
|
||||||
|
*/
|
||||||
|
angular.module('notificationService', [])
|
||||||
|
.factory('notificationService', ['$timeout', function($timeout) {
|
||||||
|
|
||||||
|
var getLocalPartFromUserId = function(user_id) {
|
||||||
|
if (!user_id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var localpartRegex = /@(.*):\w+/i
|
||||||
|
var results = localpartRegex.exec(user_id);
|
||||||
|
if (results && results.length == 2) {
|
||||||
|
return results[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
containsBingWord: function(userId, displayName, bingWords, content) {
|
||||||
|
// case-insensitive name check for user_id OR display_name if they exist
|
||||||
|
var userRegex = "";
|
||||||
|
if (userId) {
|
||||||
|
var localpart = getLocalPartFromUserId(userId);
|
||||||
|
if (localpart) {
|
||||||
|
localpart = localpart.toLocaleLowerCase();
|
||||||
|
userRegex += "\\b" + localpart + "\\b";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (displayName) {
|
||||||
|
displayName = displayName.toLocaleLowerCase();
|
||||||
|
if (userRegex.length > 0) {
|
||||||
|
userRegex += "|";
|
||||||
|
}
|
||||||
|
userRegex += "\\b" + displayName + "\\b";
|
||||||
|
}
|
||||||
|
|
||||||
|
var regexList = [new RegExp(userRegex, 'i')];
|
||||||
|
|
||||||
|
// bing word list check
|
||||||
|
if (bingWords && bingWords.length > 0) {
|
||||||
|
for (var i=0; i<bingWords.length; i++) {
|
||||||
|
var re = RegExp(bingWords[i], 'i');
|
||||||
|
regexList.push(re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.hasMatch(regexList, content);
|
||||||
|
},
|
||||||
|
|
||||||
|
hasMatch: function(regExps, content) {
|
||||||
|
if (!content || $.type(content) != "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regExps && regExps.length > 0) {
|
||||||
|
for (var i=0; i<regExps.length; i++) {
|
||||||
|
if (content.search(regExps[i]) != -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
showNotification: function(title, body, icon, onclick) {
|
||||||
|
var notification = new window.Notification(
|
||||||
|
title,
|
||||||
|
{
|
||||||
|
"body": body,
|
||||||
|
"icon": icon
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (onclick) {
|
||||||
|
notification.onclick = onclick;
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeout(function() {
|
||||||
|
notification.close();
|
||||||
|
}, 5 * 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
@ -41,6 +41,7 @@
|
|||||||
<script src="components/matrix/matrix-phone-service.js"></script>
|
<script src="components/matrix/matrix-phone-service.js"></script>
|
||||||
<script src="components/matrix/event-stream-service.js"></script>
|
<script src="components/matrix/event-stream-service.js"></script>
|
||||||
<script src="components/matrix/event-handler-service.js"></script>
|
<script src="components/matrix/event-handler-service.js"></script>
|
||||||
|
<script src="components/matrix/notification-service.js"></script>
|
||||||
<script src="components/matrix/presence-service.js"></script>
|
<script src="components/matrix/presence-service.js"></script>
|
||||||
<script src="components/fileInput/file-input-directive.js"></script>
|
<script src="components/fileInput/file-input-directive.js"></script>
|
||||||
<script src="components/fileUpload/file-upload-service.js"></script>
|
<script src="components/fileUpload/file-upload-service.js"></script>
|
||||||
|
@ -15,12 +15,22 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput'])
|
angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput'])
|
||||||
.controller('RoomController', ['$modal', '$filter', '$scope', '$timeout', '$routeParams', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventHandlerService', 'mFileUpload', 'matrixPhoneService', 'MatrixCall',
|
.controller('RoomController', ['$modal', '$filter', '$scope', '$timeout', '$routeParams', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventHandlerService', 'mFileUpload', 'matrixPhoneService', 'MatrixCall', 'notificationService',
|
||||||
function($modal, $filter, $scope, $timeout, $routeParams, $location, $rootScope, matrixService, mPresence, eventHandlerService, mFileUpload, matrixPhoneService, MatrixCall) {
|
function($modal, $filter, $scope, $timeout, $routeParams, $location, $rootScope, matrixService, mPresence, eventHandlerService, mFileUpload, matrixPhoneService, MatrixCall, notificationService) {
|
||||||
'use strict';
|
'use strict';
|
||||||
var MESSAGES_PER_PAGINATION = 30;
|
var MESSAGES_PER_PAGINATION = 30;
|
||||||
var THUMBNAIL_SIZE = 320;
|
var THUMBNAIL_SIZE = 320;
|
||||||
|
|
||||||
|
// .html needs this
|
||||||
|
$scope.containsBingWord = function(content) {
|
||||||
|
return notificationService.containsBingWord(
|
||||||
|
matrixService.config().user_id,
|
||||||
|
matrixService.config().display_name,
|
||||||
|
matrixService.config().bingWords,
|
||||||
|
content
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// Room ids. Computed and resolved in onInit
|
// Room ids. Computed and resolved in onInit
|
||||||
$scope.room_id = undefined;
|
$scope.room_id = undefined;
|
||||||
$scope.room_alias = undefined;
|
$scope.room_alias = undefined;
|
||||||
@ -191,16 +201,20 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput'])
|
|||||||
// Notify when a user joins
|
// Notify when a user joins
|
||||||
if ((document.hidden || matrixService.presence.unavailable === mPresence.getState())
|
if ((document.hidden || matrixService.presence.unavailable === mPresence.getState())
|
||||||
&& event.state_key !== $scope.state.user_id && "join" === event.membership) {
|
&& event.state_key !== $scope.state.user_id && "join" === event.membership) {
|
||||||
var notification = new window.Notification(
|
var userName = event.content.displayname;
|
||||||
event.content.displayname +
|
if (!userName) {
|
||||||
" (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", // FIXME: don't leak room_ids here
|
userName = event.state_key;
|
||||||
{
|
}
|
||||||
"body": event.content.displayname + " joined",
|
notificationService.showNotification(
|
||||||
"icon": event.content.avatar_url ? event.content.avatar_url : undefined
|
userName +
|
||||||
});
|
" (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")",
|
||||||
$timeout(function() {
|
userName + " joined",
|
||||||
notification.close();
|
event.content.avatar_url ? event.content.avatar_url : undefined,
|
||||||
}, 5 * 1000);
|
function() {
|
||||||
|
console.log("notification.onclick() room=" + event.room_id);
|
||||||
|
$rootScope.goToPage('room/' + event.room_id);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="avatar">
|
<td class="avatar">
|
||||||
<img class="avatarImage" ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.png' }}" width="32" height="32"
|
<img class="avatarImage" ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.png' }}" width="32" height="32" title="{{msg.user_id}}"
|
||||||
ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id || msg.user_id === state.user_id"/>
|
ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id || msg.user_id === state.user_id"/>
|
||||||
</td>
|
</td>
|
||||||
<td ng-class="(!msg.content.membership && ('m.room.topic' !== msg.type && 'm.room.name' !== msg.type))? (msg.content.msgtype === 'm.emote' ? 'emote text' : 'text') : 'membership text'">
|
<td ng-class="(!msg.content.membership && ('m.room.topic' !== msg.type && 'm.room.name' !== msg.type))? (msg.content.msgtype === 'm.emote' ? 'emote text' : 'text') : 'membership text'">
|
||||||
|
Loading…
Reference in New Issue
Block a user