Merge branch 'develop' into wmwragg/direct-chat-sublist
This commit is contained in:
commit
6d1f9003e2
24 changed files with 593 additions and 195 deletions
221
CHANGELOG.md
221
CHANGELOG.md
|
@ -1,3 +1,224 @@
|
||||||
|
Changes in [0.6.4-r1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.6.4-r1) (2016-08-12)
|
||||||
|
=========================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.6.4...v0.6.4-r1)
|
||||||
|
* Fix inviting multiple people
|
||||||
|
|
||||||
|
Changes in [0.6.4](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.6.4) (2016-08-11)
|
||||||
|
===================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.6.3...v0.6.4)
|
||||||
|
|
||||||
|
* Only show Autocomplete if autocomplete is enabled
|
||||||
|
[\#411](https://github.com/matrix-org/matrix-react-sdk/pull/411)
|
||||||
|
* Wmwragg/room tag menu
|
||||||
|
[\#402](https://github.com/matrix-org/matrix-react-sdk/pull/402)
|
||||||
|
* Move guest registration into the login logic
|
||||||
|
[\#407](https://github.com/matrix-org/matrix-react-sdk/pull/407)
|
||||||
|
* Better support for inviting multiple people
|
||||||
|
[\#403](https://github.com/matrix-org/matrix-react-sdk/pull/403)
|
||||||
|
* Refactor login token
|
||||||
|
[\#406](https://github.com/matrix-org/matrix-react-sdk/pull/406)
|
||||||
|
* Use the current HS for guest login
|
||||||
|
[\#405](https://github.com/matrix-org/matrix-react-sdk/pull/405)
|
||||||
|
* Various fixes and improvements to emojification.
|
||||||
|
[\#395](https://github.com/matrix-org/matrix-react-sdk/pull/395)
|
||||||
|
* Fix settings resetting on refresh
|
||||||
|
[\#404](https://github.com/matrix-org/matrix-react-sdk/pull/404)
|
||||||
|
* Avoid flashing up login screen during guest registration
|
||||||
|
[\#401](https://github.com/matrix-org/matrix-react-sdk/pull/401)
|
||||||
|
* Cancel calls to rate-limited funcs on unmount
|
||||||
|
[\#400](https://github.com/matrix-org/matrix-react-sdk/pull/400)
|
||||||
|
* Move rehydration of MatrixClients from MatrixClientPeg to SessionLoader
|
||||||
|
[\#399](https://github.com/matrix-org/matrix-react-sdk/pull/399)
|
||||||
|
* Don't show integrations header if setting not on
|
||||||
|
[\#398](https://github.com/matrix-org/matrix-react-sdk/pull/398)
|
||||||
|
* Start to factor out session-loading magic
|
||||||
|
[\#397](https://github.com/matrix-org/matrix-react-sdk/pull/397)
|
||||||
|
* Hack around a react warning
|
||||||
|
[\#396](https://github.com/matrix-org/matrix-react-sdk/pull/396)
|
||||||
|
* Add config to hide the labs section
|
||||||
|
[\#393](https://github.com/matrix-org/matrix-react-sdk/pull/393)
|
||||||
|
* Dbkr/scalar
|
||||||
|
[\#392](https://github.com/matrix-org/matrix-react-sdk/pull/392)
|
||||||
|
* Wmwragg/mute mention state fix
|
||||||
|
[\#390](https://github.com/matrix-org/matrix-react-sdk/pull/390)
|
||||||
|
* Fix long freeze when opening 'historical' section
|
||||||
|
[\#391](https://github.com/matrix-org/matrix-react-sdk/pull/391)
|
||||||
|
* Refactor UI error effects
|
||||||
|
[\#388](https://github.com/matrix-org/matrix-react-sdk/pull/388)
|
||||||
|
* Implement account deactivation
|
||||||
|
[\#381](https://github.com/matrix-org/matrix-react-sdk/pull/381)
|
||||||
|
* Don't leave isRoomPublished as undefined
|
||||||
|
[\#389](https://github.com/matrix-org/matrix-react-sdk/pull/389)
|
||||||
|
* Call the logout API when we log out
|
||||||
|
[\#377](https://github.com/matrix-org/matrix-react-sdk/pull/377)
|
||||||
|
* feat: code cleanup & emoji replacement in composer
|
||||||
|
[\#335](https://github.com/matrix-org/matrix-react-sdk/pull/335)
|
||||||
|
* Add more logging to TimelinePanel-test
|
||||||
|
[\#387](https://github.com/matrix-org/matrix-react-sdk/pull/387)
|
||||||
|
* DevicesPanel: use device_id as a placeholder
|
||||||
|
[\#386](https://github.com/matrix-org/matrix-react-sdk/pull/386)
|
||||||
|
* MemberDeviceInfo: Use the device name, where available
|
||||||
|
[\#385](https://github.com/matrix-org/matrix-react-sdk/pull/385)
|
||||||
|
* Wmwragg/mention state menu
|
||||||
|
[\#369](https://github.com/matrix-org/matrix-react-sdk/pull/369)
|
||||||
|
* fix upload for video or image files where sniffing fails
|
||||||
|
[\#383](https://github.com/matrix-org/matrix-react-sdk/pull/383)
|
||||||
|
* fix: allow up/down normally for no completions
|
||||||
|
[\#384](https://github.com/matrix-org/matrix-react-sdk/pull/384)
|
||||||
|
* fix: autocomplete to use tab instead of return
|
||||||
|
[\#382](https://github.com/matrix-org/matrix-react-sdk/pull/382)
|
||||||
|
* strip (IRC) displayname suffix from autocomplete
|
||||||
|
[\#375](https://github.com/matrix-org/matrix-react-sdk/pull/375)
|
||||||
|
* Include rooms with 1 person invited
|
||||||
|
[\#379](https://github.com/matrix-org/matrix-react-sdk/pull/379)
|
||||||
|
* Fix 'start new direct chat'
|
||||||
|
[\#378](https://github.com/matrix-org/matrix-react-sdk/pull/378)
|
||||||
|
* Fix warnings from MessageComposer
|
||||||
|
[\#376](https://github.com/matrix-org/matrix-react-sdk/pull/376)
|
||||||
|
* New voice and video call buttons
|
||||||
|
[\#371](https://github.com/matrix-org/matrix-react-sdk/pull/371)
|
||||||
|
* Silence some more react warnings
|
||||||
|
[\#373](https://github.com/matrix-org/matrix-react-sdk/pull/373)
|
||||||
|
* Fix warnings emanating from Velociraptor elements
|
||||||
|
[\#372](https://github.com/matrix-org/matrix-react-sdk/pull/372)
|
||||||
|
* Wmwragg/button updates
|
||||||
|
[\#353](https://github.com/matrix-org/matrix-react-sdk/pull/353)
|
||||||
|
* Implement device management UI
|
||||||
|
[\#370](https://github.com/matrix-org/matrix-react-sdk/pull/370)
|
||||||
|
* Factor EditableTextContainer out of ChangeDisplayName
|
||||||
|
[\#368](https://github.com/matrix-org/matrix-react-sdk/pull/368)
|
||||||
|
* Stop the Avatar classes setting properties on <span>s
|
||||||
|
[\#367](https://github.com/matrix-org/matrix-react-sdk/pull/367)
|
||||||
|
* Remove relayoutOnUpdate prop on gemini-scrollbar
|
||||||
|
[\#366](https://github.com/matrix-org/matrix-react-sdk/pull/366)
|
||||||
|
* Fix bug where vector freezes on power level event
|
||||||
|
[\#364](https://github.com/matrix-org/matrix-react-sdk/pull/364)
|
||||||
|
* Refactor MatrixClientPeg
|
||||||
|
[\#361](https://github.com/matrix-org/matrix-react-sdk/pull/361)
|
||||||
|
* Fix 'start chat' button on MemberInfo
|
||||||
|
[\#363](https://github.com/matrix-org/matrix-react-sdk/pull/363)
|
||||||
|
* Bump dependency versions
|
||||||
|
[\#362](https://github.com/matrix-org/matrix-react-sdk/pull/362)
|
||||||
|
* Fix tab complete order properly
|
||||||
|
[\#360](https://github.com/matrix-org/matrix-react-sdk/pull/360)
|
||||||
|
* Add removeListener for account data listener
|
||||||
|
[\#359](https://github.com/matrix-org/matrix-react-sdk/pull/359)
|
||||||
|
* Set the device_id on pre-login MatrixClient
|
||||||
|
[\#358](https://github.com/matrix-org/matrix-react-sdk/pull/358)
|
||||||
|
* Wmwragg/mention state indicator round 2
|
||||||
|
[\#357](https://github.com/matrix-org/matrix-react-sdk/pull/357)
|
||||||
|
* Support for disabling/enabling URL previews per-user, per-room and per-user-
|
||||||
|
per-room
|
||||||
|
[\#356](https://github.com/matrix-org/matrix-react-sdk/pull/356)
|
||||||
|
* Use HS proxy API for requestToken on adding email
|
||||||
|
[\#336](https://github.com/matrix-org/matrix-react-sdk/pull/336)
|
||||||
|
* Error if email already in use when resetting pw
|
||||||
|
[\#337](https://github.com/matrix-org/matrix-react-sdk/pull/337)
|
||||||
|
* Fix enourmous video bug
|
||||||
|
[\#355](https://github.com/matrix-org/matrix-react-sdk/pull/355)
|
||||||
|
* Add support for sending uploaded content as m.video
|
||||||
|
[\#354](https://github.com/matrix-org/matrix-react-sdk/pull/354)
|
||||||
|
* Order tab complete by most recently spoke
|
||||||
|
[\#341](https://github.com/matrix-org/matrix-react-sdk/pull/341)
|
||||||
|
* Wmwragg/spinner fix
|
||||||
|
[\#350](https://github.com/matrix-org/matrix-react-sdk/pull/350)
|
||||||
|
* Now showing three dots when hovering over the badge
|
||||||
|
[\#352](https://github.com/matrix-org/matrix-react-sdk/pull/352)
|
||||||
|
* Fix unpublishing room in room settings
|
||||||
|
[\#351](https://github.com/matrix-org/matrix-react-sdk/pull/351)
|
||||||
|
* Fix race when creating rooms where invite list can be blank
|
||||||
|
[\#347](https://github.com/matrix-org/matrix-react-sdk/pull/347)
|
||||||
|
* improve wording of MemberInfo's start chat button.
|
||||||
|
[\#348](https://github.com/matrix-org/matrix-react-sdk/pull/348)
|
||||||
|
* Revert "Amends react template and removes opening image in lightbox"
|
||||||
|
[\#346](https://github.com/matrix-org/matrix-react-sdk/pull/346)
|
||||||
|
* Wmwragg/modal restyle
|
||||||
|
[\#345](https://github.com/matrix-org/matrix-react-sdk/pull/345)
|
||||||
|
* Amends react template and removes opening image in lightbox
|
||||||
|
[\#343](https://github.com/matrix-org/matrix-react-sdk/pull/343)
|
||||||
|
* Remove the member list loading hack
|
||||||
|
[\#344](https://github.com/matrix-org/matrix-react-sdk/pull/344)
|
||||||
|
* CSS classes to colour offline users differently
|
||||||
|
[\#342](https://github.com/matrix-org/matrix-react-sdk/pull/342)
|
||||||
|
* Listen for the new lastPreseceTs event
|
||||||
|
[\#340](https://github.com/matrix-org/matrix-react-sdk/pull/340)
|
||||||
|
* Fix filtering user list by ID
|
||||||
|
[\#339](https://github.com/matrix-org/matrix-react-sdk/pull/339)
|
||||||
|
* Update tab completion list when we have a room
|
||||||
|
[\#338](https://github.com/matrix-org/matrix-react-sdk/pull/338)
|
||||||
|
* JS code style guide
|
||||||
|
[\#330](https://github.com/matrix-org/matrix-react-sdk/pull/330)
|
||||||
|
* Error on registration if email taken
|
||||||
|
[\#334](https://github.com/matrix-org/matrix-react-sdk/pull/334)
|
||||||
|
* feat: render unicode emoji as emojione images
|
||||||
|
[\#332](https://github.com/matrix-org/matrix-react-sdk/pull/332)
|
||||||
|
* feat: unblacklist img tags with data URIs
|
||||||
|
[\#333](https://github.com/matrix-org/matrix-react-sdk/pull/333)
|
||||||
|
* Autocomplete fixes
|
||||||
|
[\#331](https://github.com/matrix-org/matrix-react-sdk/pull/331)
|
||||||
|
* Better autocomplete
|
||||||
|
[\#296](https://github.com/matrix-org/matrix-react-sdk/pull/296)
|
||||||
|
* feat: add and configure eslint
|
||||||
|
[\#329](https://github.com/matrix-org/matrix-react-sdk/pull/329)
|
||||||
|
* Fix user links
|
||||||
|
[\#326](https://github.com/matrix-org/matrix-react-sdk/pull/326)
|
||||||
|
* Fix ordering of Memberlist
|
||||||
|
[\#327](https://github.com/matrix-org/matrix-react-sdk/pull/327)
|
||||||
|
* Display an error message if room not found
|
||||||
|
[\#325](https://github.com/matrix-org/matrix-react-sdk/pull/325)
|
||||||
|
* Implement device blocking
|
||||||
|
[\#324](https://github.com/matrix-org/matrix-react-sdk/pull/324)
|
||||||
|
* Remove /encrypt command
|
||||||
|
[\#322](https://github.com/matrix-org/matrix-react-sdk/pull/322)
|
||||||
|
* RoomSettings: add encryption setting
|
||||||
|
[\#321](https://github.com/matrix-org/matrix-react-sdk/pull/321)
|
||||||
|
* Fix a pair of warnings from RoomSettings
|
||||||
|
[\#320](https://github.com/matrix-org/matrix-react-sdk/pull/320)
|
||||||
|
* RoomSettings: refactor permissions calculations
|
||||||
|
[\#319](https://github.com/matrix-org/matrix-react-sdk/pull/319)
|
||||||
|
* Fix https://github.com/vector-im/vector-web/issues/1679
|
||||||
|
[\#318](https://github.com/matrix-org/matrix-react-sdk/pull/318)
|
||||||
|
* Fix /join to be consistent with the other code
|
||||||
|
[\#317](https://github.com/matrix-org/matrix-react-sdk/pull/317)
|
||||||
|
* UserSettings: fix the displayed version of the react-sdk
|
||||||
|
[\#316](https://github.com/matrix-org/matrix-react-sdk/pull/316)
|
||||||
|
* Show canonical alias in URL bar
|
||||||
|
[\#314](https://github.com/matrix-org/matrix-react-sdk/pull/314)
|
||||||
|
* Some basic tests for RoomView
|
||||||
|
[\#313](https://github.com/matrix-org/matrix-react-sdk/pull/313)
|
||||||
|
* Support for making devices unverified
|
||||||
|
[\#315](https://github.com/matrix-org/matrix-react-sdk/pull/315)
|
||||||
|
* Fix eventListener warning
|
||||||
|
[\#312](https://github.com/matrix-org/matrix-react-sdk/pull/312)
|
||||||
|
* Fix peeking and member list vanishing
|
||||||
|
[\#307](https://github.com/matrix-org/matrix-react-sdk/pull/307)
|
||||||
|
* Use different keys for new MessageComposerInput
|
||||||
|
[\#311](https://github.com/matrix-org/matrix-react-sdk/pull/311)
|
||||||
|
* Fix RTE escaping, HTML output with breaks
|
||||||
|
[\#310](https://github.com/matrix-org/matrix-react-sdk/pull/310)
|
||||||
|
* Fix cursor bug, persist editor mode & rte default
|
||||||
|
[\#308](https://github.com/matrix-org/matrix-react-sdk/pull/308)
|
||||||
|
* Rich Text Editor
|
||||||
|
[\#292](https://github.com/matrix-org/matrix-react-sdk/pull/292)
|
||||||
|
* Hide e2e features if not enabled
|
||||||
|
[\#306](https://github.com/matrix-org/matrix-react-sdk/pull/306)
|
||||||
|
* Add experimental "Labs" section to settings
|
||||||
|
[\#305](https://github.com/matrix-org/matrix-react-sdk/pull/305)
|
||||||
|
* Make the room directory join rooms by alias
|
||||||
|
[\#304](https://github.com/matrix-org/matrix-react-sdk/pull/304)
|
||||||
|
* Factor out common parts of room creation
|
||||||
|
[\#303](https://github.com/matrix-org/matrix-react-sdk/pull/303)
|
||||||
|
* Fix spinner-of-doom in member info for guests
|
||||||
|
[\#302](https://github.com/matrix-org/matrix-react-sdk/pull/302)
|
||||||
|
* Support for marking devices as verified
|
||||||
|
[\#300](https://github.com/matrix-org/matrix-react-sdk/pull/300)
|
||||||
|
* Make the config optional
|
||||||
|
[\#301](https://github.com/matrix-org/matrix-react-sdk/pull/301)
|
||||||
|
* Pass brand parameter down to Notifications
|
||||||
|
[\#299](https://github.com/matrix-org/matrix-react-sdk/pull/299)
|
||||||
|
* Second attempt at fixing the Velocity memory leak
|
||||||
|
[\#298](https://github.com/matrix-org/matrix-react-sdk/pull/298)
|
||||||
|
|
||||||
Changes in [0.6.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.6.3) (2016-06-03)
|
Changes in [0.6.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v0.6.3) (2016-06-03)
|
||||||
===================================================================================================
|
===================================================================================================
|
||||||
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.6.2...v0.6.3)
|
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v0.6.2...v0.6.3)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "matrix-react-sdk",
|
"name": "matrix-react-sdk",
|
||||||
"version": "0.6.3",
|
"version": "0.6.4-r1",
|
||||||
"description": "SDK for matrix.org using React",
|
"description": "SDK for matrix.org using React",
|
||||||
"author": "matrix.org",
|
"author": "matrix.org",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
"linkifyjs": "^2.0.0-beta.4",
|
"linkifyjs": "^2.0.0-beta.4",
|
||||||
"lodash": "^4.13.1",
|
"lodash": "^4.13.1",
|
||||||
"marked": "^0.3.5",
|
"marked": "^0.3.5",
|
||||||
"matrix-js-sdk": "matrix-org/matrix-js-sdk#develop",
|
"matrix-js-sdk": "0.5.5",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"react": "^15.2.1",
|
"react": "^15.2.1",
|
||||||
|
|
|
@ -273,8 +273,11 @@ function _onAction(payload) {
|
||||||
break;
|
break;
|
||||||
case 'incoming_call':
|
case 'incoming_call':
|
||||||
if (module.exports.getAnyActiveCall()) {
|
if (module.exports.getAnyActiveCall()) {
|
||||||
payload.call.hangup("busy");
|
// ignore multiple incoming calls. in future, we may want a line-1/line-2 setup.
|
||||||
return; // don't allow >1 call to be received, hangup newer one.
|
// we avoid rejecting with "busy" in case the user wants to answer it on a different device.
|
||||||
|
// in future we could signal a "local busy" as a warning to the caller.
|
||||||
|
// see https://github.com/vector-im/vector-web/issues/1964
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the runtime env doesn't do VoIP, stop here.
|
// if the runtime env doesn't do VoIP, stop here.
|
||||||
|
|
|
@ -69,7 +69,7 @@ var sanitizeHtmlParams = {
|
||||||
allowedAttributes: {
|
allowedAttributes: {
|
||||||
// custom ones first:
|
// custom ones first:
|
||||||
font: [ 'color' ], // custom to matrix
|
font: [ 'color' ], // custom to matrix
|
||||||
a: [ 'href', 'name', 'target' ], // remote target: custom to matrix
|
a: [ 'href', 'name', 'target', 'rel' ], // remote target: custom to matrix
|
||||||
// We don't currently allow img itself by default, but this
|
// We don't currently allow img itself by default, but this
|
||||||
// would make sense if we did
|
// would make sense if we did
|
||||||
img: [ 'src' ],
|
img: [ 'src' ],
|
||||||
|
@ -92,6 +92,7 @@ var sanitizeHtmlParams = {
|
||||||
else {
|
else {
|
||||||
attribs.target = '_blank';
|
attribs.target = '_blank';
|
||||||
}
|
}
|
||||||
|
attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/
|
||||||
return { tagName: tagName, attribs : attribs };
|
return { tagName: tagName, attribs : attribs };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -69,6 +69,7 @@ export function loadSession(opts) {
|
||||||
let enableGuest = opts.enableGuest || false;
|
let enableGuest = opts.enableGuest || false;
|
||||||
const guestHsUrl = opts.guestHsUrl;
|
const guestHsUrl = opts.guestHsUrl;
|
||||||
const guestIsUrl = opts.guestIsUrl;
|
const guestIsUrl = opts.guestIsUrl;
|
||||||
|
const defaultDeviceDisplayName = opts.defaultDeviceDisplayName;
|
||||||
|
|
||||||
if (fragmentQueryParams.client_secret && fragmentQueryParams.sid) {
|
if (fragmentQueryParams.client_secret && fragmentQueryParams.sid) {
|
||||||
// this happens during email validation: the email contains a link to the
|
// this happens during email validation: the email contains a link to the
|
||||||
|
@ -87,7 +88,7 @@ export function loadSession(opts) {
|
||||||
if (!realQueryParams.homeserver) {
|
if (!realQueryParams.homeserver) {
|
||||||
console.warn("Cannot log in with token: can't determine HS URL to use");
|
console.warn("Cannot log in with token: can't determine HS URL to use");
|
||||||
} else {
|
} else {
|
||||||
return _loginWithToken(realQueryParams);
|
return _loginWithToken(realQueryParams, defaultDeviceDisplayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,23 +112,29 @@ export function loadSession(opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableGuest) {
|
if (enableGuest) {
|
||||||
return _registerAsGuest(guestHsUrl, guestIsUrl);
|
return _registerAsGuest(guestHsUrl, guestIsUrl, defaultDeviceDisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fall back to login screen
|
// fall back to login screen
|
||||||
return q();
|
return q();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _loginWithToken(queryParams) {
|
function _loginWithToken(queryParams, defaultDeviceDisplayName) {
|
||||||
// create a temporary MatrixClient to do the login
|
// create a temporary MatrixClient to do the login
|
||||||
var client = Matrix.createClient({
|
var client = Matrix.createClient({
|
||||||
baseUrl: queryParams.homeserver,
|
baseUrl: queryParams.homeserver,
|
||||||
});
|
});
|
||||||
|
|
||||||
return client.loginWithToken(queryParams.loginToken).then(function(data) {
|
return client.login(
|
||||||
|
"m.login.token", {
|
||||||
|
token: queryParams.loginToken,
|
||||||
|
initial_device_display_name: defaultDeviceDisplayName,
|
||||||
|
},
|
||||||
|
).then(function(data) {
|
||||||
console.log("Logged in with token");
|
console.log("Logged in with token");
|
||||||
setLoggedIn({
|
setLoggedIn({
|
||||||
userId: data.user_id,
|
userId: data.user_id,
|
||||||
|
deviceId: data.device_id,
|
||||||
accessToken: data.access_token,
|
accessToken: data.access_token,
|
||||||
homeserverUrl: queryParams.homeserver,
|
homeserverUrl: queryParams.homeserver,
|
||||||
identityServerUrl: queryParams.identityServer,
|
identityServerUrl: queryParams.identityServer,
|
||||||
|
@ -139,14 +146,26 @@ function _loginWithToken(queryParams) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _registerAsGuest(hsUrl, isUrl) {
|
function _registerAsGuest(hsUrl, isUrl, defaultDeviceDisplayName) {
|
||||||
console.log("Doing guest login on %s", hsUrl);
|
console.log("Doing guest login on %s", hsUrl);
|
||||||
|
|
||||||
MatrixClientPeg.replaceUsingUrls(hsUrl, isUrl);
|
// TODO: we should probably de-duplicate this and Signup.Login.loginAsGuest.
|
||||||
return MatrixClientPeg.get().registerGuest().then((creds) => {
|
// Not really sure where the right home for it is.
|
||||||
|
|
||||||
|
// create a temporary MatrixClient to do the login
|
||||||
|
var client = Matrix.createClient({
|
||||||
|
baseUrl: hsUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
return client.registerGuest({
|
||||||
|
body: {
|
||||||
|
initial_device_display_name: defaultDeviceDisplayName,
|
||||||
|
},
|
||||||
|
}).then((creds) => {
|
||||||
console.log("Registered as guest: %s", creds.user_id);
|
console.log("Registered as guest: %s", creds.user_id);
|
||||||
setLoggedIn({
|
setLoggedIn({
|
||||||
userId: creds.user_id,
|
userId: creds.user_id,
|
||||||
|
deviceId: creds.device_id,
|
||||||
accessToken: creds.access_token,
|
accessToken: creds.access_token,
|
||||||
homeserverUrl: hsUrl,
|
homeserverUrl: hsUrl,
|
||||||
identityServerUrl: isUrl,
|
identityServerUrl: isUrl,
|
||||||
|
@ -166,6 +185,7 @@ function _restoreFromLocalStorage() {
|
||||||
const is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org';
|
const is_url = localStorage.getItem("mx_is_url") || 'https://matrix.org';
|
||||||
const access_token = localStorage.getItem("mx_access_token");
|
const access_token = localStorage.getItem("mx_access_token");
|
||||||
const user_id = localStorage.getItem("mx_user_id");
|
const user_id = localStorage.getItem("mx_user_id");
|
||||||
|
const device_id = localStorage.getItem("mx_device_id");
|
||||||
|
|
||||||
let is_guest;
|
let is_guest;
|
||||||
if (localStorage.getItem("mx_is_guest") !== null) {
|
if (localStorage.getItem("mx_is_guest") !== null) {
|
||||||
|
@ -179,6 +199,7 @@ function _restoreFromLocalStorage() {
|
||||||
console.log("Restoring session for %s", user_id);
|
console.log("Restoring session for %s", user_id);
|
||||||
setLoggedIn({
|
setLoggedIn({
|
||||||
userId: user_id,
|
userId: user_id,
|
||||||
|
deviceId: device_id,
|
||||||
accessToken: access_token,
|
accessToken: access_token,
|
||||||
homeserverUrl: hs_url,
|
homeserverUrl: hs_url,
|
||||||
identityServerUrl: is_url,
|
identityServerUrl: is_url,
|
||||||
|
@ -206,10 +227,19 @@ export function setLoggedIn(credentials) {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem("mx_hs_url", credentials.homeserverUrl);
|
localStorage.setItem("mx_hs_url", credentials.homeserverUrl);
|
||||||
localStorage.setItem("mx_is_url", credentials.identityServerUrl);
|
localStorage.setItem("mx_is_url", credentials.identityServerUrl);
|
||||||
|
|
||||||
localStorage.setItem("mx_user_id", credentials.userId);
|
localStorage.setItem("mx_user_id", credentials.userId);
|
||||||
localStorage.setItem("mx_access_token", credentials.accessToken);
|
localStorage.setItem("mx_access_token", credentials.accessToken);
|
||||||
localStorage.setItem("mx_is_guest", JSON.stringify(credentials.guest));
|
localStorage.setItem("mx_is_guest", JSON.stringify(credentials.guest));
|
||||||
|
|
||||||
|
// if we didn't get a deviceId from the login, leave mx_device_id unset,
|
||||||
|
// rather than setting it to "undefined".
|
||||||
|
//
|
||||||
|
// (in this case MatrixClient doesn't bother with the crypto stuff
|
||||||
|
// - that's fine for us).
|
||||||
|
if (credentials.deviceId) {
|
||||||
|
localStorage.setItem("mx_device_id", credentials.deviceId);
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Session persisted for %s", credentials.userId);
|
console.log("Session persisted for %s", credentials.userId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Error using local storage: can't persist session!", e);
|
console.warn("Error using local storage: can't persist session!", e);
|
||||||
|
@ -286,7 +316,7 @@ export function onLoggedOut() {
|
||||||
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
|
if (hsUrl) window.localStorage.setItem("mx_hs_url", hsUrl);
|
||||||
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
|
if (isUrl) window.localStorage.setItem("mx_is_url", isUrl);
|
||||||
}
|
}
|
||||||
_stopMatrixClient();
|
stopMatrixClient();
|
||||||
|
|
||||||
dis.dispatch({action: 'on_logged_out'});
|
dis.dispatch({action: 'on_logged_out'});
|
||||||
}
|
}
|
||||||
|
@ -294,11 +324,14 @@ export function onLoggedOut() {
|
||||||
/**
|
/**
|
||||||
* Stop all the background processes related to the current client
|
* Stop all the background processes related to the current client
|
||||||
*/
|
*/
|
||||||
function _stopMatrixClient() {
|
export function stopMatrixClient() {
|
||||||
Notifier.stop();
|
Notifier.stop();
|
||||||
UserActivity.stop();
|
UserActivity.stop();
|
||||||
Presence.stop();
|
Presence.stop();
|
||||||
MatrixClientPeg.get().stopClient();
|
var cli = MatrixClientPeg.get();
|
||||||
MatrixClientPeg.get().removeAllListeners();
|
if (cli) {
|
||||||
|
cli.stopClient();
|
||||||
|
cli.removeAllListeners();
|
||||||
MatrixClientPeg.unset();
|
MatrixClientPeg.unset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,21 +21,11 @@ import utils from 'matrix-js-sdk/lib/utils';
|
||||||
|
|
||||||
const localStorage = window.localStorage;
|
const localStorage = window.localStorage;
|
||||||
|
|
||||||
function deviceId() {
|
|
||||||
// XXX: is Math.random()'s deterministicity a problem here?
|
|
||||||
var id = Math.floor(Math.random()*16777215).toString(16);
|
|
||||||
id = "W" + "000000".substring(id.length) + id;
|
|
||||||
if (localStorage) {
|
|
||||||
id = localStorage.getItem("mx_device_id") || id;
|
|
||||||
localStorage.setItem("mx_device_id", id);
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MatrixClientCreds {
|
interface MatrixClientCreds {
|
||||||
homeserverUrl: string,
|
homeserverUrl: string,
|
||||||
identityServerUrl: string,
|
identityServerUrl: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
|
deviceId: string,
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
guest: boolean,
|
guest: boolean,
|
||||||
}
|
}
|
||||||
|
@ -67,26 +57,12 @@ class MatrixClientPeg {
|
||||||
this.matrixClient = null;
|
this.matrixClient = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace this MatrixClientPeg's client with a client instance that has
|
|
||||||
* Home Server / Identity Server URLs but no credentials
|
|
||||||
*/
|
|
||||||
replaceUsingUrls(hs_url, is_url) {
|
|
||||||
this._replaceClient(hs_url, is_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace this MatrixClientPeg's client with a client instance that has
|
* Replace this MatrixClientPeg's client with a client instance that has
|
||||||
* Home Server / Identity Server URLs and active credentials
|
* Home Server / Identity Server URLs and active credentials
|
||||||
*/
|
*/
|
||||||
replaceUsingCreds(creds: MatrixClientCreds) {
|
replaceUsingCreds(creds: MatrixClientCreds) {
|
||||||
this._replaceClient(
|
this._createClient(creds);
|
||||||
creds.homeserverUrl,
|
|
||||||
creds.identityServerUrl,
|
|
||||||
creds.userId,
|
|
||||||
creds.accessToken,
|
|
||||||
creds.guest,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
|
@ -96,32 +72,29 @@ class MatrixClientPeg {
|
||||||
this.get().startClient(opts);
|
this.get().startClient(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
_replaceClient(hs_url, is_url, user_id, access_token, isGuest) {
|
|
||||||
this._createClient(hs_url, is_url, user_id, access_token, isGuest);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCredentials(): MatrixClientCreds {
|
getCredentials(): MatrixClientCreds {
|
||||||
return {
|
return {
|
||||||
homeserverUrl: this.matrixClient.baseUrl,
|
homeserverUrl: this.matrixClient.baseUrl,
|
||||||
identityServerUrl: this.matrixClient.idBaseUrl,
|
identityServerUrl: this.matrixClient.idBaseUrl,
|
||||||
userId: this.matrixClient.credentials.userId,
|
userId: this.matrixClient.credentials.userId,
|
||||||
|
deviceId: this.matrixClient.getDeviceId(),
|
||||||
accessToken: this.matrixClient.getAccessToken(),
|
accessToken: this.matrixClient.getAccessToken(),
|
||||||
guest: this.matrixClient.isGuest(),
|
guest: this.matrixClient.isGuest(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_createClient(hs_url, is_url, user_id, access_token, isGuest) {
|
_createClient(creds: MatrixClientCreds) {
|
||||||
var opts = {
|
var opts = {
|
||||||
baseUrl: hs_url,
|
baseUrl: creds.homeserverUrl,
|
||||||
idBaseUrl: is_url,
|
idBaseUrl: creds.identityServerUrl,
|
||||||
accessToken: access_token,
|
accessToken: creds.accessToken,
|
||||||
userId: user_id,
|
userId: creds.userId,
|
||||||
|
deviceId: creds.deviceId,
|
||||||
timelineSupport: true,
|
timelineSupport: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (localStorage) {
|
if (localStorage) {
|
||||||
opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage);
|
opts.sessionStore = new Matrix.WebStorageSessionStore(localStorage);
|
||||||
opts.deviceId = deviceId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.matrixClient = Matrix.createClient(opts);
|
this.matrixClient = Matrix.createClient(opts);
|
||||||
|
@ -130,7 +103,7 @@ class MatrixClientPeg {
|
||||||
// potential number of event listeners is quite high.
|
// potential number of event listeners is quite high.
|
||||||
this.matrixClient.setMaxListeners(500);
|
this.matrixClient.setMaxListeners(500);
|
||||||
|
|
||||||
this.matrixClient.setGuest(Boolean(isGuest));
|
this.matrixClient.setGuest(Boolean(creds.guest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
164
src/RoomNotifs.js
Normal file
164
src/RoomNotifs.js
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import MatrixClientPeg from './MatrixClientPeg';
|
||||||
|
import PushProcessor from 'matrix-js-sdk/lib/pushprocessor';
|
||||||
|
import q from 'q';
|
||||||
|
|
||||||
|
export const ALL_MESSAGES_LOUD = 'all_messages_loud';
|
||||||
|
export const ALL_MESSAGES = 'all_messages';
|
||||||
|
export const MENTIONS_ONLY = 'mentions_only';
|
||||||
|
export const MUTE = 'mute';
|
||||||
|
|
||||||
|
export function getRoomNotifsState(roomId) {
|
||||||
|
if (MatrixClientPeg.get().isGuest()) return RoomNotifs.ALL_MESSAGES;
|
||||||
|
|
||||||
|
// look through the override rules for a rule affecting this room:
|
||||||
|
// if one exists, it will take precedence.
|
||||||
|
const muteRule = findOverrideMuteRule(roomId);
|
||||||
|
if (muteRule) {
|
||||||
|
return MUTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for everything else, look at the room rule.
|
||||||
|
const roomRule = MatrixClientPeg.get().getRoomPushRule('global', roomId);
|
||||||
|
|
||||||
|
// XXX: We have to assume the default is to notify for all messages
|
||||||
|
// (in particular this will be 'wrong' for one to one rooms because
|
||||||
|
// they will notify loudly for all messages)
|
||||||
|
if (!roomRule || !roomRule.enabled) return ALL_MESSAGES;
|
||||||
|
|
||||||
|
// a mute at the room level will still allow mentions
|
||||||
|
// to notify
|
||||||
|
if (isMuteRule(roomRule)) return MENTIONS_ONLY;
|
||||||
|
|
||||||
|
const actionsObject = PushProcessor.actionListToActionsObject(roomRule.actions);
|
||||||
|
if (actionsObject.tweaks.sound) return ALL_MESSAGES_LOUD;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setRoomNotifsState(roomId, newState) {
|
||||||
|
if (newState == MUTE) {
|
||||||
|
return setRoomNotifsStateMuted(roomId);
|
||||||
|
} else {
|
||||||
|
return setRoomNotifsStateUnmuted(roomId, newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRoomNotifsStateMuted(roomId) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
// delete the room rule
|
||||||
|
const roomRule = cli.getRoomPushRule('global', roomId);
|
||||||
|
if (roomRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'room', roomRule.rule_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// add/replace an override rule to squelch everything in this room
|
||||||
|
// NB. We use the room ID as the name of this rule too, although this
|
||||||
|
// is an override rule, not a room rule: it still pertains to this room
|
||||||
|
// though, so using the room ID as the rule ID is logical and prevents
|
||||||
|
// duplicate copies of the rule.
|
||||||
|
promises.push(cli.addPushRule('global', 'override', roomId, {
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
kind: 'event_match',
|
||||||
|
key: 'room_id',
|
||||||
|
pattern: roomId,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
'dont_notify',
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
return q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setRoomNotifsStateUnmuted(roomId, newState) {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
const overrideMuteRule = findOverrideMuteRule(roomId);
|
||||||
|
if (overrideMuteRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'override', overrideMuteRule.rule_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newState == 'all_messages') {
|
||||||
|
const roomRule = cli.getRoomPushRule('global', roomId);
|
||||||
|
if (roomRule) {
|
||||||
|
promises.push(cli.deletePushRule('global', 'room', roomRule.rule_id));
|
||||||
|
}
|
||||||
|
} else if (newState == 'mentions_only') {
|
||||||
|
promises.push(cli.addPushRule('global', 'room', roomId, {
|
||||||
|
actions: [
|
||||||
|
'dont_notify',
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
// https://matrix.org/jira/browse/SPEC-400
|
||||||
|
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
|
||||||
|
} else if ('all_messages_loud') {
|
||||||
|
promises.push(cli.addPushRule('global', 'room', roomId, {
|
||||||
|
actions: [
|
||||||
|
'notify',
|
||||||
|
{
|
||||||
|
set_tweak: 'sound',
|
||||||
|
value: 'default',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
// https://matrix.org/jira/browse/SPEC-400
|
||||||
|
promises.push(cli.setPushRuleEnabled('global', 'room', roomId, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOverrideMuteRule(roomId) {
|
||||||
|
for (const rule of MatrixClientPeg.get().pushRules['global'].override) {
|
||||||
|
if (isRuleForRoom(roomId, rule)) {
|
||||||
|
if (isMuteRule(rule) && rule.enabled) {
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRuleForRoom(roomId, rule) {
|
||||||
|
if (rule.conditions.length !== 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cond = rule.conditions[0];
|
||||||
|
if (
|
||||||
|
cond.kind == 'event_match' &&
|
||||||
|
cond.key == 'room_id' &&
|
||||||
|
cond.pattern == roomId
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMuteRule(rule) {
|
||||||
|
return (
|
||||||
|
rule.actions.length == 1 &&
|
||||||
|
rule.actions[0] == 'dont_notify'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -34,8 +34,10 @@ class ScalarAuthClient {
|
||||||
defer.reject(err);
|
defer.reject(err);
|
||||||
} else if (response.statusCode / 100 !== 2) {
|
} else if (response.statusCode / 100 !== 2) {
|
||||||
defer.reject({statusCode: response.statusCode});
|
defer.reject({statusCode: response.statusCode});
|
||||||
|
} else if (!body || !body.scalar_token) {
|
||||||
|
defer.reject(new Error("Missing scalar_token in response"));
|
||||||
} else {
|
} else {
|
||||||
defer.resolve(body.access_token);
|
defer.resolve(body.scalar_token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
109
src/Signup.js
109
src/Signup.js
|
@ -1,4 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
import Matrix from "matrix-js-sdk";
|
||||||
|
|
||||||
var MatrixClientPeg = require("./MatrixClientPeg");
|
var MatrixClientPeg = require("./MatrixClientPeg");
|
||||||
var SignupStages = require("./SignupStages");
|
var SignupStages = require("./SignupStages");
|
||||||
var dis = require("./dispatcher");
|
var dis = require("./dispatcher");
|
||||||
|
@ -11,9 +14,10 @@ const EMAIL_STAGE_TYPE = "m.login.email.identity";
|
||||||
* storage of HS/IS URLs.
|
* storage of HS/IS URLs.
|
||||||
*/
|
*/
|
||||||
class Signup {
|
class Signup {
|
||||||
constructor(hsUrl, isUrl) {
|
constructor(hsUrl, isUrl, opts) {
|
||||||
this._hsUrl = hsUrl;
|
this._hsUrl = hsUrl;
|
||||||
this._isUrl = isUrl;
|
this._isUrl = isUrl;
|
||||||
|
this._defaultDeviceDisplayName = opts.defaultDeviceDisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHomeserverUrl() {
|
getHomeserverUrl() {
|
||||||
|
@ -31,14 +35,25 @@ class Signup {
|
||||||
setIdentityServerUrl(isUrl) {
|
setIdentityServerUrl(isUrl) {
|
||||||
this._isUrl = isUrl;
|
this._isUrl = isUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a temporary MatrixClient, which can be used for login or register
|
||||||
|
* requests.
|
||||||
|
*/
|
||||||
|
_createTemporaryClient() {
|
||||||
|
return Matrix.createClient({
|
||||||
|
baseUrl: this._hsUrl,
|
||||||
|
idBaseUrl: this._isUrl,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registration logic class
|
* Registration logic class
|
||||||
*/
|
*/
|
||||||
class Register extends Signup {
|
class Register extends Signup {
|
||||||
constructor(hsUrl, isUrl) {
|
constructor(hsUrl, isUrl, opts) {
|
||||||
super(hsUrl, isUrl);
|
super(hsUrl, isUrl, opts);
|
||||||
this.setStep("START");
|
this.setStep("START");
|
||||||
this.data = null; // from the server
|
this.data = null; // from the server
|
||||||
// random other stuff (e.g. query params, NOT params from the server)
|
// random other stuff (e.g. query params, NOT params from the server)
|
||||||
|
@ -106,19 +121,11 @@ class Register extends Signup {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
const client = this._createTemporaryClient();
|
||||||
// feels a bit wrong to be clobbering the global client for something we
|
return this._tryRegister(client);
|
||||||
// don't even know if it'll work, but we'll leave this here for now to
|
|
||||||
// not complicate matters further. It would be nicer to isolate this
|
|
||||||
// logic entirely from the rest of the app though.
|
|
||||||
MatrixClientPeg.replaceUsingUrls(
|
|
||||||
this._hsUrl,
|
|
||||||
this._isUrl
|
|
||||||
);
|
|
||||||
return this._tryRegister();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_tryRegister(authDict, poll_for_success) {
|
_tryRegister(client, authDict, poll_for_success) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var bindEmail;
|
var bindEmail;
|
||||||
|
@ -129,7 +136,8 @@ class Register extends Signup {
|
||||||
bindEmail = true;
|
bindEmail = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatrixClientPeg.get().register(
|
// TODO need to figure out how to send the device display name to /register.
|
||||||
|
return client.register(
|
||||||
this.username, this.password, this.params.sessionId, authDict, bindEmail,
|
this.username, this.password, this.params.sessionId, authDict, bindEmail,
|
||||||
this.guestAccessToken
|
this.guestAccessToken
|
||||||
).then(function(result) {
|
).then(function(result) {
|
||||||
|
@ -152,7 +160,7 @@ class Register extends Signup {
|
||||||
console.log("Active flow => %s", JSON.stringify(flow));
|
console.log("Active flow => %s", JSON.stringify(flow));
|
||||||
var flowStage = self.firstUncompletedStage(flow);
|
var flowStage = self.firstUncompletedStage(flow);
|
||||||
if (flowStage != self.activeStage) {
|
if (flowStage != self.activeStage) {
|
||||||
return self.startStage(flowStage).catch(function(err) {
|
return self._startStage(client, flowStage).catch(function(err) {
|
||||||
self.setStep('START');
|
self.setStep('START');
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
@ -161,7 +169,7 @@ class Register extends Signup {
|
||||||
}
|
}
|
||||||
if (poll_for_success) {
|
if (poll_for_success) {
|
||||||
return q.delay(5000).then(function() {
|
return q.delay(5000).then(function() {
|
||||||
return self._tryRegister(authDict, poll_for_success);
|
return self._tryRegister(client, authDict, poll_for_success);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Authorisation failed!");
|
throw new Error("Authorisation failed!");
|
||||||
|
@ -201,7 +209,7 @@ class Register extends Signup {
|
||||||
return completed.indexOf(stageType) !== -1;
|
return completed.indexOf(stageType) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
startStage(stageName) {
|
_startStage(client, stageName) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.setStep(`STEP_${stageName}`);
|
this.setStep(`STEP_${stageName}`);
|
||||||
var StageClass = SignupStages[stageName];
|
var StageClass = SignupStages[stageName];
|
||||||
|
@ -210,12 +218,12 @@ class Register extends Signup {
|
||||||
throw new Error("Unknown stage: " + stageName);
|
throw new Error("Unknown stage: " + stageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var stage = new StageClass(MatrixClientPeg.get(), this);
|
var stage = new StageClass(client, this);
|
||||||
this.activeStage = stage;
|
this.activeStage = stage;
|
||||||
return stage.complete().then(function(request) {
|
return stage.complete().then(function(request) {
|
||||||
if (request.auth) {
|
if (request.auth) {
|
||||||
console.log("Stage %s is returning an auth dict", stageName);
|
console.log("Stage %s is returning an auth dict", stageName);
|
||||||
return self._tryRegister(request.auth, request.poll_for_success);
|
return self._tryRegister(client, request.auth, request.poll_for_success);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// never resolve the promise chain. This is for things like email auth
|
// never resolve the promise chain. This is for things like email auth
|
||||||
|
@ -263,14 +271,6 @@ class Register extends Signup {
|
||||||
}
|
}
|
||||||
|
|
||||||
recheckState() {
|
recheckState() {
|
||||||
// feels a bit wrong to be clobbering the global client for something we
|
|
||||||
// don't even know if it'll work, but we'll leave this here for now to
|
|
||||||
// not complicate matters further. It would be nicer to isolate this
|
|
||||||
// logic entirely from the rest of the app though.
|
|
||||||
MatrixClientPeg.replaceUsingUrls(
|
|
||||||
this._hsUrl,
|
|
||||||
this._isUrl
|
|
||||||
);
|
|
||||||
// We've been given a bunch of data from a previous register step,
|
// We've been given a bunch of data from a previous register step,
|
||||||
// this only happens for email auth currently. It's kinda ming we need
|
// this only happens for email auth currently. It's kinda ming we need
|
||||||
// to know this though. A better solution would be to ask the stages if
|
// to know this though. A better solution would be to ask the stages if
|
||||||
|
@ -281,7 +281,8 @@ class Register extends Signup {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.params.hasEmailInfo) {
|
if (this.params.hasEmailInfo) {
|
||||||
this.registrationPromise = this.startStage(EMAIL_STAGE_TYPE);
|
const client = this._createTemporaryClient();
|
||||||
|
this.registrationPromise = this._startStage(client, EMAIL_STAGE_TYPE);
|
||||||
}
|
}
|
||||||
return this.registrationPromise;
|
return this.registrationPromise;
|
||||||
}
|
}
|
||||||
|
@ -296,8 +297,8 @@ class Register extends Signup {
|
||||||
|
|
||||||
|
|
||||||
class Login extends Signup {
|
class Login extends Signup {
|
||||||
constructor(hsUrl, isUrl, fallbackHsUrl) {
|
constructor(hsUrl, isUrl, fallbackHsUrl, opts) {
|
||||||
super(hsUrl, isUrl);
|
super(hsUrl, isUrl, opts);
|
||||||
this._fallbackHsUrl = fallbackHsUrl;
|
this._fallbackHsUrl = fallbackHsUrl;
|
||||||
this._currentFlowIndex = 0;
|
this._currentFlowIndex = 0;
|
||||||
this._flows = [];
|
this._flows = [];
|
||||||
|
@ -305,15 +306,8 @@ class Login extends Signup {
|
||||||
|
|
||||||
getFlows() {
|
getFlows() {
|
||||||
var self = this;
|
var self = this;
|
||||||
// feels a bit wrong to be clobbering the global client for something we
|
var client = this._createTemporaryClient();
|
||||||
// don't even know if it'll work, but we'll leave this here for now to
|
return client.loginFlows().then(function(result) {
|
||||||
// not complicate matters further. It would be nicer to isolate this
|
|
||||||
// logic entirely from the rest of the app though.
|
|
||||||
MatrixClientPeg.replaceUsingUrls(
|
|
||||||
this._hsUrl,
|
|
||||||
this._isUrl
|
|
||||||
);
|
|
||||||
return MatrixClientPeg.get().loginFlows().then(function(result) {
|
|
||||||
self._flows = result.flows;
|
self._flows = result.flows;
|
||||||
self._currentFlowIndex = 0;
|
self._currentFlowIndex = 0;
|
||||||
// technically the UI should display options for all flows for the
|
// technically the UI should display options for all flows for the
|
||||||
|
@ -334,10 +328,15 @@ class Login extends Signup {
|
||||||
}
|
}
|
||||||
|
|
||||||
loginAsGuest() {
|
loginAsGuest() {
|
||||||
MatrixClientPeg.replaceUsingUrls(this._hsUrl, this._isUrl);
|
var client = this._createTemporaryClient();
|
||||||
return MatrixClientPeg.get().registerGuest().then((creds) => {
|
return client.registerGuest({
|
||||||
|
body: {
|
||||||
|
initial_device_display_name: this._defaultDeviceDisplayName,
|
||||||
|
},
|
||||||
|
}).then((creds) => {
|
||||||
return {
|
return {
|
||||||
userId: creds.user_id,
|
userId: creds.user_id,
|
||||||
|
deviceId: creds.device_id,
|
||||||
accessToken: creds.access_token,
|
accessToken: creds.access_token,
|
||||||
homeserverUrl: this._hsUrl,
|
homeserverUrl: this._hsUrl,
|
||||||
identityServerUrl: this._isUrl,
|
identityServerUrl: this._isUrl,
|
||||||
|
@ -357,7 +356,8 @@ class Login extends Signup {
|
||||||
var self = this;
|
var self = this;
|
||||||
var isEmail = username.indexOf("@") > 0;
|
var isEmail = username.indexOf("@") > 0;
|
||||||
var loginParams = {
|
var loginParams = {
|
||||||
password: pass
|
password: pass,
|
||||||
|
initial_device_display_name: this._defaultDeviceDisplayName,
|
||||||
};
|
};
|
||||||
if (isEmail) {
|
if (isEmail) {
|
||||||
loginParams.medium = 'email';
|
loginParams.medium = 'email';
|
||||||
|
@ -366,11 +366,13 @@ class Login extends Signup {
|
||||||
loginParams.user = username;
|
loginParams.user = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatrixClientPeg.get().login('m.login.password', loginParams).then(function(data) {
|
var client = this._createTemporaryClient();
|
||||||
|
return client.login('m.login.password', loginParams).then(function(data) {
|
||||||
return q({
|
return q({
|
||||||
homeserverUrl: self._hsUrl,
|
homeserverUrl: self._hsUrl,
|
||||||
identityServerUrl: self._isUrl,
|
identityServerUrl: self._isUrl,
|
||||||
userId: data.user_id,
|
userId: data.user_id,
|
||||||
|
deviceId: data.device_id,
|
||||||
accessToken: data.access_token
|
accessToken: data.access_token
|
||||||
});
|
});
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
|
@ -384,25 +386,20 @@ class Login extends Signup {
|
||||||
'Incorrect username and/or password.'
|
'Incorrect username and/or password.'
|
||||||
);
|
);
|
||||||
if (self._fallbackHsUrl) {
|
if (self._fallbackHsUrl) {
|
||||||
// as per elsewhere, it would be much nicer to not replace the global
|
var fbClient = Matrix.createClient({
|
||||||
// client just to try an alternate HS
|
baseUrl: self._fallbackHsUrl,
|
||||||
MatrixClientPeg.replaceUsingUrls(
|
idBaseUrl: this._isUrl,
|
||||||
self._fallbackHsUrl,
|
});
|
||||||
self._isUrl
|
|
||||||
);
|
return fbClient.login('m.login.password', loginParams).then(function(data) {
|
||||||
return MatrixClientPeg.get().login('m.login.password', loginParams).then(function(data) {
|
|
||||||
return q({
|
return q({
|
||||||
homeserverUrl: self._fallbackHsUrl,
|
homeserverUrl: self._fallbackHsUrl,
|
||||||
identityServerUrl: self._isUrl,
|
identityServerUrl: self._isUrl,
|
||||||
userId: data.user_id,
|
userId: data.user_id,
|
||||||
|
deviceId: data.device_id,
|
||||||
accessToken: data.access_token
|
accessToken: data.access_token
|
||||||
});
|
});
|
||||||
}, function(fallback_error) {
|
}, function(fallback_error) {
|
||||||
// We also have to put the default back again if it fails...
|
|
||||||
MatrixClientPeg.replaceUsingUrls(
|
|
||||||
this._hsUrl,
|
|
||||||
this._isUrl
|
|
||||||
);
|
|
||||||
// throw the original error
|
// throw the original error
|
||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
|
@ -94,7 +94,7 @@ CommandEntry.fromCommands = function(commandArray) {
|
||||||
|
|
||||||
class MemberEntry extends Entry {
|
class MemberEntry extends Entry {
|
||||||
constructor(member) {
|
constructor(member) {
|
||||||
super(member.name || member.userId);
|
super((member.name || member.userId).replace(' (IRC)', ''));
|
||||||
this.member = member;
|
this.member = member;
|
||||||
this.kind = 'member';
|
this.kind = 'member';
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,10 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
// called when the session load completes
|
// called when the session load completes
|
||||||
onLoadCompleted: React.PropTypes.func,
|
onLoadCompleted: React.PropTypes.func,
|
||||||
|
|
||||||
|
// displayname, if any, to set on the device when logging
|
||||||
|
// in/registering.
|
||||||
|
defaultDeviceDisplayName: React.PropTypes.string,
|
||||||
},
|
},
|
||||||
|
|
||||||
PageTypes: {
|
PageTypes: {
|
||||||
|
@ -185,6 +189,7 @@ module.exports = React.createClass({
|
||||||
enableGuest: this.props.enableGuest,
|
enableGuest: this.props.enableGuest,
|
||||||
guestHsUrl: this.getCurrentHsUrl(),
|
guestHsUrl: this.getCurrentHsUrl(),
|
||||||
guestIsUrl: this.getCurrentIsUrl(),
|
guestIsUrl: this.getCurrentIsUrl(),
|
||||||
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
||||||
}).done(()=>{
|
}).done(()=>{
|
||||||
// stuff this through the dispatcher so that it happens
|
// stuff this through the dispatcher so that it happens
|
||||||
// after the on_logged_in action.
|
// after the on_logged_in action.
|
||||||
|
@ -193,7 +198,7 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
this._stopMatrixClient();
|
Lifecycle.stopMatrixClient();
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
document.removeEventListener("keydown", this.onKeyDown);
|
document.removeEventListener("keydown", this.onKeyDown);
|
||||||
window.removeEventListener("focus", this.onFocus);
|
window.removeEventListener("focus", this.onFocus);
|
||||||
|
@ -601,16 +606,6 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// stop all the background processes related to the current client
|
|
||||||
_stopMatrixClient: function() {
|
|
||||||
Notifier.stop();
|
|
||||||
UserActivity.stop();
|
|
||||||
Presence.stop();
|
|
||||||
MatrixClientPeg.get().stopClient();
|
|
||||||
MatrixClientPeg.get().removeAllListeners();
|
|
||||||
MatrixClientPeg.unset();
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyDown: function(ev) {
|
onKeyDown: function(ev) {
|
||||||
/*
|
/*
|
||||||
// Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers
|
// Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers
|
||||||
|
@ -935,10 +930,8 @@ module.exports = React.createClass({
|
||||||
var NewVersionBar = sdk.getComponent('globals.NewVersionBar');
|
var NewVersionBar = sdk.getComponent('globals.NewVersionBar');
|
||||||
var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword');
|
var ForgotPassword = sdk.getComponent('structures.login.ForgotPassword');
|
||||||
|
|
||||||
// work out the HS URL prompts we should show for
|
// console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen +
|
||||||
|
// "; logged_in="+this.state.logged_in+"; ready="+this.state.ready);
|
||||||
console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen +
|
|
||||||
"; logged_in="+this.state.logged_in+"; ready="+this.state.ready);
|
|
||||||
|
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
var Spinner = sdk.getComponent('elements.Spinner');
|
var Spinner = sdk.getComponent('elements.Spinner');
|
||||||
|
@ -1051,6 +1044,7 @@ module.exports = React.createClass({
|
||||||
customHsUrl={this.getCurrentHsUrl()}
|
customHsUrl={this.getCurrentHsUrl()}
|
||||||
customIsUrl={this.getCurrentIsUrl()}
|
customIsUrl={this.getCurrentIsUrl()}
|
||||||
registrationUrl={this.props.registrationUrl}
|
registrationUrl={this.props.registrationUrl}
|
||||||
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||||
onLoggedIn={this.onRegistered}
|
onLoggedIn={this.onRegistered}
|
||||||
onLoginClick={this.onLoginClick}
|
onLoginClick={this.onLoginClick}
|
||||||
onRegisterClick={this.onRegisterClick}
|
onRegisterClick={this.onRegisterClick}
|
||||||
|
@ -1077,6 +1071,7 @@ module.exports = React.createClass({
|
||||||
customHsUrl={this.getCurrentHsUrl()}
|
customHsUrl={this.getCurrentHsUrl()}
|
||||||
customIsUrl={this.getCurrentIsUrl()}
|
customIsUrl={this.getCurrentIsUrl()}
|
||||||
fallbackHsUrl={this.getFallbackHsUrl()}
|
fallbackHsUrl={this.getFallbackHsUrl()}
|
||||||
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||||
onForgotPasswordClick={this.onForgotPasswordClick}
|
onForgotPasswordClick={this.onForgotPasswordClick}
|
||||||
enableGuest={this.props.enableGuest}
|
enableGuest={this.props.enableGuest}
|
||||||
onCancelClick={this.guestCreds ? this.onReturnToGuestClick : null}
|
onCancelClick={this.guestCreds ? this.onReturnToGuestClick : null}
|
||||||
|
|
|
@ -44,6 +44,8 @@ module.exports = React.createClass({
|
||||||
// different home server without confusing users.
|
// different home server without confusing users.
|
||||||
fallbackHsUrl: React.PropTypes.string,
|
fallbackHsUrl: React.PropTypes.string,
|
||||||
|
|
||||||
|
defaultDeviceDisplayName: React.PropTypes.string,
|
||||||
|
|
||||||
// login shouldn't know or care how registration is done.
|
// login shouldn't know or care how registration is done.
|
||||||
onRegisterClick: React.PropTypes.func.isRequired,
|
onRegisterClick: React.PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
@ -136,7 +138,9 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
var fallbackHsUrl = hsUrl == this.props.defaultHsUrl ? this.props.fallbackHsUrl : null;
|
var fallbackHsUrl = hsUrl == this.props.defaultHsUrl ? this.props.fallbackHsUrl : null;
|
||||||
|
|
||||||
var loginLogic = new Signup.Login(hsUrl, isUrl, fallbackHsUrl);
|
var loginLogic = new Signup.Login(hsUrl, isUrl, fallbackHsUrl, {
|
||||||
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
||||||
|
});
|
||||||
this._loginLogic = loginLogic;
|
this._loginLogic = loginLogic;
|
||||||
|
|
||||||
loginLogic.getFlows().then(function(flows) {
|
loginLogic.getFlows().then(function(flows) {
|
||||||
|
|
|
@ -45,6 +45,9 @@ module.exports = React.createClass({
|
||||||
email: React.PropTypes.string,
|
email: React.PropTypes.string,
|
||||||
username: React.PropTypes.string,
|
username: React.PropTypes.string,
|
||||||
guestAccessToken: React.PropTypes.string,
|
guestAccessToken: React.PropTypes.string,
|
||||||
|
|
||||||
|
defaultDeviceDisplayName: React.PropTypes.string,
|
||||||
|
|
||||||
// registration shouldn't know or care how login is done.
|
// registration shouldn't know or care how login is done.
|
||||||
onLoginClick: React.PropTypes.func.isRequired,
|
onLoginClick: React.PropTypes.func.isRequired,
|
||||||
onCancelClick: React.PropTypes.func
|
onCancelClick: React.PropTypes.func
|
||||||
|
@ -71,7 +74,9 @@ module.exports = React.createClass({
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
// attach this to the instance rather than this.state since it isn't UI
|
// attach this to the instance rather than this.state since it isn't UI
|
||||||
this.registerLogic = new Signup.Register(
|
this.registerLogic = new Signup.Register(
|
||||||
this.props.customHsUrl, this.props.customIsUrl
|
this.props.customHsUrl, this.props.customIsUrl, {
|
||||||
|
defaultDeviceDisplayName: this.props.defaultDeviceDisplayName,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
this.registerLogic.setClientSecret(this.props.clientSecret);
|
this.registerLogic.setClientSecret(this.props.clientSecret);
|
||||||
this.registerLogic.setSessionId(this.props.sessionId);
|
this.registerLogic.setSessionId(this.props.sessionId);
|
||||||
|
@ -154,6 +159,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
self.props.onLoggedIn({
|
self.props.onLoggedIn({
|
||||||
userId: response.user_id,
|
userId: response.user_id,
|
||||||
|
deviceId: response.device_id,
|
||||||
homeserverUrl: self.registerLogic.getHomeserverUrl(),
|
homeserverUrl: self.registerLogic.getHomeserverUrl(),
|
||||||
identityServerUrl: self.registerLogic.getIdentityServerUrl(),
|
identityServerUrl: self.registerLogic.getIdentityServerUrl(),
|
||||||
accessToken: response.access_token
|
accessToken: response.access_token
|
||||||
|
|
|
@ -60,7 +60,7 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<span className="mx_MFileBody">
|
<span className="mx_MFileBody">
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
<a href={cli.mxcUrlToHttp(content.url)} target="_blank" rel="noopener">
|
||||||
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
||||||
Download {text}
|
Download {text}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -134,7 +134,7 @@ module.exports = React.createClass({
|
||||||
onMouseLeave={this.onImageLeave} />
|
onMouseLeave={this.onImageLeave} />
|
||||||
</a>
|
</a>
|
||||||
<div className="mx_MImageBody_download">
|
<div className="mx_MImageBody_download">
|
||||||
<a href={cli.mxcUrlToHttp(content.url)} target="_blank">
|
<a href={cli.mxcUrlToHttp(content.url)} target="_blank" rel="noopener">
|
||||||
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
<TintableSvg src="img/download.svg" width="12" height="14"/>
|
||||||
Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" })
|
Download {content.body} ({ content.info && content.info.size ? filesize(content.info.size) : "Unknown size" })
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -123,7 +123,7 @@ module.exports = React.createClass({
|
||||||
<div className="mx_LinkPreviewWidget" >
|
<div className="mx_LinkPreviewWidget" >
|
||||||
{ img }
|
{ img }
|
||||||
<div className="mx_LinkPreviewWidget_caption">
|
<div className="mx_LinkPreviewWidget_caption">
|
||||||
<div className="mx_LinkPreviewWidget_title"><a href={ this.props.link } target="_blank">{ p["og:title"] }</a></div>
|
<div className="mx_LinkPreviewWidget_title"><a href={ this.props.link } target="_blank" rel="noopener">{ p["og:title"] }</a></div>
|
||||||
<div className="mx_LinkPreviewWidget_siteName">{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }</div>
|
<div className="mx_LinkPreviewWidget_siteName">{ p["og:site_name"] ? (" - " + p["og:site_name"]) : null }</div>
|
||||||
<div className="mx_LinkPreviewWidget_description" ref="description">
|
<div className="mx_LinkPreviewWidget_description" ref="description">
|
||||||
{ p["og:description"] }
|
{ p["og:description"] }
|
||||||
|
|
|
@ -67,6 +67,11 @@ module.exports = React.createClass({
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this._cancelDeviceList = null;
|
this._cancelDeviceList = null;
|
||||||
|
|
||||||
|
// only display the devices list if our client supports E2E *and* the
|
||||||
|
// feature is enabled in the user settings
|
||||||
|
this._enableDevices = MatrixClientPeg.get().isCryptoEnabled() &&
|
||||||
|
UserSettingsStore.isFeatureEnabled("e2e_encryption");
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
existingOneToOneRoomId: this.getExistingOneToOneRoomId()
|
existingOneToOneRoomId: this.getExistingOneToOneRoomId()
|
||||||
});
|
});
|
||||||
|
@ -147,6 +152,10 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onDeviceVerificationChanged: function(userId, device) {
|
onDeviceVerificationChanged: function(userId, device) {
|
||||||
|
if (!this._enableDevices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (userId == this.props.member.userId) {
|
if (userId == this.props.member.userId) {
|
||||||
// no need to re-download the whole thing; just update our copy of
|
// no need to re-download the whole thing; just update our copy of
|
||||||
// the list.
|
// the list.
|
||||||
|
@ -170,6 +179,10 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_downloadDeviceList: function(member) {
|
_downloadDeviceList: function(member) {
|
||||||
|
if (!this._enableDevices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var cancelled = false;
|
var cancelled = false;
|
||||||
this._cancelDeviceList = function() { cancelled = true; }
|
this._cancelDeviceList = function() { cancelled = true; }
|
||||||
|
|
||||||
|
@ -532,7 +545,7 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderDevices: function() {
|
_renderDevices: function() {
|
||||||
if (!UserSettingsStore.isFeatureEnabled("e2e_encryption")) {
|
if (!this._enableDevices) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_doInvite(address) {
|
_doInvite(address) {
|
||||||
Invite.inviteToRoom(self.props.roomId, address).catch((err) => {
|
Invite.inviteToRoom(this.props.roomId, address).catch((err) => {
|
||||||
if (err !== null) {
|
if (err !== null) {
|
||||||
console.error("Failed to invite: %s", JSON.stringify(err));
|
console.error("Failed to invite: %s", JSON.stringify(err));
|
||||||
if (err.errcode == 'M_FORBIDDEN') {
|
if (err.errcode == 'M_FORBIDDEN') {
|
||||||
|
@ -196,7 +196,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
self.setState({
|
this.setState({
|
||||||
inviting: false
|
inviting: false
|
||||||
});
|
});
|
||||||
// XXX: hacky focus on the invite box
|
// XXX: hacky focus on the invite box
|
||||||
|
@ -207,7 +207,7 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}).done();
|
}).done();
|
||||||
self.setState({
|
this.setState({
|
||||||
inviting: true
|
inviting: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -283,7 +283,7 @@ module.exports = React.createClass({
|
||||||
if (inputs.length == 1) {
|
if (inputs.length == 1) {
|
||||||
// for a single address, we just send the invite
|
// for a single address, we just send the invite
|
||||||
promise.done(() => {
|
promise.done(() => {
|
||||||
this.doInvite(inputs[0]);
|
this._doInvite(inputs[0]);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// if there are several, display the confirmation/progress dialog
|
// if there are several, display the confirmation/progress dialog
|
||||||
|
|
|
@ -47,16 +47,6 @@ module.exports = React.createClass({
|
||||||
tags[tagName] = ['yep'];
|
tags[tagName] = ['yep'];
|
||||||
});
|
});
|
||||||
|
|
||||||
var areNotifsMuted = false;
|
|
||||||
if (!MatrixClientPeg.get().isGuest()) {
|
|
||||||
var roomPushRule = MatrixClientPeg.get().getRoomPushRule("global", this.props.room.roomId);
|
|
||||||
if (roomPushRule) {
|
|
||||||
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
|
||||||
areNotifsMuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: this._yankValueFromEvent("m.room.name", "name"),
|
name: this._yankValueFromEvent("m.room.name", "name"),
|
||||||
topic: this._yankValueFromEvent("m.room.topic", "topic"),
|
topic: this._yankValueFromEvent("m.room.topic", "topic"),
|
||||||
|
@ -66,7 +56,6 @@ module.exports = React.createClass({
|
||||||
power_levels_changed: false,
|
power_levels_changed: false,
|
||||||
tags_changed: false,
|
tags_changed: false,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
areNotifsMuted: areNotifsMuted,
|
|
||||||
// isRoomPublished is loaded async in componentWillMount so when the component
|
// isRoomPublished is loaded async in componentWillMount so when the component
|
||||||
// inits, the saved value will always be undefined, however getInitialState()
|
// inits, the saved value will always be undefined, however getInitialState()
|
||||||
// is also called from the saving code so we must return the correct value here
|
// is also called from the saving code so we must return the correct value here
|
||||||
|
@ -188,12 +177,6 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.state.areNotifsMuted !== originalState.areNotifsMuted) {
|
|
||||||
promises.push(MatrixClientPeg.get().setRoomMutePushRule(
|
|
||||||
"global", roomId, this.state.areNotifsMuted
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// power levels
|
// power levels
|
||||||
var powerLevels = this._getPowerLevels();
|
var powerLevels = this._getPowerLevels();
|
||||||
if (powerLevels) {
|
if (powerLevels) {
|
||||||
|
@ -647,12 +630,6 @@ module.exports = React.createClass({
|
||||||
{ tagsSection }
|
{ tagsSection }
|
||||||
|
|
||||||
<div className="mx_RoomSettings_toggles">
|
<div className="mx_RoomSettings_toggles">
|
||||||
<label>
|
|
||||||
<input type="checkbox" disabled={ cli.isGuest() }
|
|
||||||
onChange={this._onToggle.bind(this, "areNotifsMuted", true, false)}
|
|
||||||
defaultChecked={this.state.areNotifsMuted}/>
|
|
||||||
'Mention only' notifications for this room
|
|
||||||
</label>
|
|
||||||
<div className="mx_RoomSettings_settings">
|
<div className="mx_RoomSettings_settings">
|
||||||
<h3>Who can access this room?</h3>
|
<h3>Who can access this room?</h3>
|
||||||
{ inviteGuestWarning }
|
{ inviteGuestWarning }
|
||||||
|
|
|
@ -22,6 +22,7 @@ var dis = require("../../../dispatcher");
|
||||||
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
var MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
var ContextualMenu = require('../../structures/ContextualMenu');
|
var ContextualMenu = require('../../structures/ContextualMenu');
|
||||||
|
var RoomNotifs = require('../../../RoomNotifs');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'RoomTile',
|
displayName: 'RoomTile',
|
||||||
|
@ -43,43 +44,41 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
var areNotifsMuted = false;
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
if (!cli.isGuest()) {
|
|
||||||
var roomPushRule = cli.getRoomPushRule("global", this.props.room.roomId);
|
|
||||||
if (roomPushRule) {
|
|
||||||
if (0 <= roomPushRule.actions.indexOf("dont_notify")) {
|
|
||||||
areNotifsMuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return({
|
return({
|
||||||
hover : false,
|
hover : false,
|
||||||
badgeHover : false,
|
badgeHover : false,
|
||||||
notificationTagMenu: false,
|
notificationTagMenu: false,
|
||||||
roomTagMenu: false,
|
roomTagMenu: false,
|
||||||
areNotifsMuted: areNotifsMuted,
|
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onAction: function(payload) {
|
_shouldShowNotifBadge: function() {
|
||||||
switch (payload.action) {
|
const showBadgeInStates = [RoomNotifs.ALL_MESSAGES, RoomNotifs.ALL_MESSAGES_LOUD];
|
||||||
case 'notification_change':
|
return showBadgeInStates.indexOf(this.state.notifState) > -1;
|
||||||
// Is the notification about this room?
|
},
|
||||||
if (payload.roomId === this.props.room.roomId) {
|
|
||||||
this.setState( { areNotifsMuted : payload.areNotifsMuted });
|
_shouldShowMentionBadge: function() {
|
||||||
}
|
return this.state.notifState != RoomNotifs.MUTE;
|
||||||
break;
|
},
|
||||||
|
|
||||||
|
onAccountData: function(accountDataEvent) {
|
||||||
|
if (accountDataEvent.getType() == 'm.push_rules') {
|
||||||
|
this.setState({
|
||||||
|
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidMount: function() {
|
componentWillMount: function() {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
dis.unregister(this.dispatcherRef);
|
var cli = MatrixClientPeg.get();
|
||||||
|
if (cli) {
|
||||||
|
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick: function() {
|
onClick: function() {
|
||||||
|
@ -179,15 +178,19 @@ module.exports = React.createClass({
|
||||||
var notificationCount = this.props.room.getUnreadNotificationCount();
|
var notificationCount = this.props.room.getUnreadNotificationCount();
|
||||||
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
||||||
|
|
||||||
|
const notifBadges = notificationCount > 0 && this._shouldShowNotifBadge();
|
||||||
|
const mentionBadges = this.props.highlight && this._shouldShowMentionBadge();
|
||||||
|
const badges = notifBadges || mentionBadges;
|
||||||
|
|
||||||
var classes = classNames({
|
var classes = classNames({
|
||||||
'mx_RoomTile': true,
|
'mx_RoomTile': true,
|
||||||
'mx_RoomTile_selected': this.props.selected,
|
'mx_RoomTile_selected': this.props.selected,
|
||||||
'mx_RoomTile_unread': this.props.unread,
|
'mx_RoomTile_unread': this.props.unread,
|
||||||
'mx_RoomTile_unreadNotify': notificationCount > 0 && !this.state.areNotifsMuted,
|
'mx_RoomTile_unreadNotify': notifBadges,
|
||||||
'mx_RoomTile_highlight': this.props.highlight,
|
'mx_RoomTile_highlight': mentionBadges,
|
||||||
'mx_RoomTile_invited': (me && me.membership == 'invite'),
|
'mx_RoomTile_invited': (me && me.membership == 'invite'),
|
||||||
'mx_RoomTile_notificationTagMenu': this.state.notificationTagMenu,
|
'mx_RoomTile_notificationTagMenu': this.state.notificationTagMenu,
|
||||||
'mx_RoomTile_noBadges': !(this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted))
|
'mx_RoomTile_noBadges': !badges,
|
||||||
});
|
});
|
||||||
|
|
||||||
var avatarClasses = classNames({
|
var avatarClasses = classNames({
|
||||||
|
@ -214,7 +217,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
if (this.state.badgeHover || this.state.notificationTagMenu) {
|
if (this.state.badgeHover || this.state.notificationTagMenu) {
|
||||||
badgeContent = "\u00B7\u00B7\u00B7";
|
badgeContent = "\u00B7\u00B7\u00B7";
|
||||||
} else if (this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted)) {
|
} else if (badges) {
|
||||||
var limitedCount = (notificationCount > 99) ? '99+' : notificationCount;
|
var limitedCount = (notificationCount > 99) ? '99+' : notificationCount;
|
||||||
badgeContent = notificationCount ? limitedCount : '!';
|
badgeContent = notificationCount ? limitedCount : '!';
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,7 +233,7 @@ module.exports = React.createClass({
|
||||||
var nameClasses = classNames({
|
var nameClasses = classNames({
|
||||||
'mx_RoomTile_name': true,
|
'mx_RoomTile_name': true,
|
||||||
'mx_RoomTile_invite': this.props.isInvite,
|
'mx_RoomTile_invite': this.props.isInvite,
|
||||||
'mx_RoomTile_badgeShown': this.props.highlight || (notificationCount > 0 && !this.state.areNotifsMuted) || this.state.badgeHover || this.state.notificationTagMenu,
|
'mx_RoomTile_badgeShown': badges || this.state.badgeHover || this.state.notificationTagMenu,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.props.selected) {
|
if (this.props.selected) {
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default class DevicesPanel extends React.Component {
|
||||||
(error) => {
|
(error) => {
|
||||||
if (this._unmounted) { return; }
|
if (this._unmounted) { return; }
|
||||||
var errtxt;
|
var errtxt;
|
||||||
if (err.httpStatus == 404) {
|
if (error.httpStatus == 404) {
|
||||||
// 404 probably means the HS doesn't yet support the API.
|
// 404 probably means the HS doesn't yet support the API.
|
||||||
errtxt = "Your home server does not support device management.";
|
errtxt = "Your home server does not support device management.";
|
||||||
} else {
|
} else {
|
||||||
|
@ -127,6 +127,7 @@ export default class DevicesPanel extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<div className="mx_DevicesPanel_header">
|
<div className="mx_DevicesPanel_header">
|
||||||
|
<div className="mx_DevicesPanel_deviceId">ID</div>
|
||||||
<div className="mx_DevicesPanel_deviceName">Name</div>
|
<div className="mx_DevicesPanel_deviceName">Name</div>
|
||||||
<div className="mx_DevicesPanel_deviceLastSeen">Last seen</div>
|
<div className="mx_DevicesPanel_deviceLastSeen">Last seen</div>
|
||||||
<div className="mx_DevicesPanel_deviceButtons"></div>
|
<div className="mx_DevicesPanel_deviceButtons"></div>
|
||||||
|
|
|
@ -109,6 +109,9 @@ export default class DevicesPanelEntry extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_DevicesPanel_device">
|
<div className="mx_DevicesPanel_device">
|
||||||
|
<div className="mx_DevicesPanel_deviceId">
|
||||||
|
{device.device_id}
|
||||||
|
</div>
|
||||||
<div className="mx_DevicesPanel_deviceName">
|
<div className="mx_DevicesPanel_deviceName">
|
||||||
<EditableTextContainer initialValue={device.display_name}
|
<EditableTextContainer initialValue={device.display_name}
|
||||||
onSubmit={this._onDisplayNameChanged}
|
onSubmit={this._onDisplayNameChanged}
|
||||||
|
|
|
@ -137,6 +137,10 @@ matrixLinkify.options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
linkAttributes: {
|
||||||
|
rel: 'noopener',
|
||||||
|
},
|
||||||
|
|
||||||
target: function(href, type) {
|
target: function(href, type) {
|
||||||
if (type === 'url') {
|
if (type === 'url') {
|
||||||
if (href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
|
if (href.match(matrixLinkify.VECTOR_URL_PATTERN)) {
|
||||||
|
|
|
@ -50,8 +50,7 @@ module.exports.stubClient = function() {
|
||||||
//
|
//
|
||||||
// 'sandbox.restore()' doesn't work correctly on inherited methods,
|
// 'sandbox.restore()' doesn't work correctly on inherited methods,
|
||||||
// so we do this for each method
|
// so we do this for each method
|
||||||
var methods = ['get', 'unset', 'replaceUsingUrls',
|
var methods = ['get', 'unset', 'replaceUsingCreds'];
|
||||||
'replaceUsingCreds'];
|
|
||||||
for (var i = 0; i < methods.length; i++) {
|
for (var i = 0; i < methods.length; i++) {
|
||||||
sandbox.stub(peg, methods[i]);
|
sandbox.stub(peg, methods[i]);
|
||||||
}
|
}
|
||||||
|
@ -184,4 +183,3 @@ module.exports.mkStubRoom = function() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue