Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Support for room upgrades #2122

Merged
merged 4 commits into from
Aug 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
@import "./views/dialogs/_EncryptedEventDialog.scss";
@import "./views/dialogs/_GroupAddressPicker.scss";
@import "./views/dialogs/_QuestionDialog.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@import "./views/dialogs/_SetEmailDialog.scss";
@import "./views/dialogs/_SetMxIdDialog.scss";
@import "./views/dialogs/_SetPasswordDialog.scss";
Expand Down Expand Up @@ -99,6 +100,7 @@
@import "./views/rooms/_RoomSettings.scss";
@import "./views/rooms/_RoomTile.scss";
@import "./views/rooms/_RoomTooltip.scss";
@import "./views/rooms/_RoomUpgradeWarningBar.scss";
@import "./views/rooms/_SearchBar.scss";
@import "./views/rooms/_SearchableEntityList.scss";
@import "./views/rooms/_Stickers.scss";
Expand Down
19 changes: 19 additions & 0 deletions res/css/views/dialogs/_RoomUpgradeDialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Copyright 2018 New Vector 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.
*/

.mx_RoomUpgradeDialog {
padding-right: 70px;
}
6 changes: 6 additions & 0 deletions res/css/views/rooms/_RoomSettings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@ limitations under the License.
margin-bottom: 20px;
}

.mx_RoomSettings_upgradeButton,
.mx_RoomSettings_leaveButton,
.mx_RoomSettings_unbanButton {
@mixin mx_DialogButton;
position: relative;
margin-right: 8px;
}

.mx_RoomSettings_upgradeButton,
.mx_RoomSettings_leaveButton:hover,
.mx_RoomSettings_unbanButton:hover {
@mixin mx_DialogButton_hover;
}

.mx_RoomSettings_upgradeButton.danger {
@mixin mx_DialogButton_danger;
}

.mx_RoomSettings_integrationsButton_error {
position: relative;
cursor: not-allowed;
Expand Down
48 changes: 48 additions & 0 deletions res/css/views/rooms/_RoomUpgradeWarningBar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Copyright 2018 New Vector 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.
*/

.mx_RoomUpgradeWarningBar {
text-align: center;
height: 176px;
background-color: $event-selected-color;
align-items: center;
flex-direction: column;
justify-content: center;
display: flex;
background-color: $preview-bar-bg-color;
-webkit-align-items: center;
padding-left: 20px;
padding-right: 20px;
}

.mx_RoomUpgradeWarningBar_header {
color: $warning-color;
font-weight: bold;
}

.mx_RoomUpgradeWarningBar_body {
color: $warning-color;
}

.mx_RoomUpgradeWarningBar_upgradelink {
color: $warning-color;
text-decoration: underline;
}

.mx_RoomUpgradeWarningBar_small {
color: $greyed-fg-color;
font-size: 70%;
}
4 changes: 4 additions & 0 deletions res/themes/light/css/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ $progressbar-color: #000;
outline: none;
}

@define-mixin mx_DialogButton_danger {
background-color: $warning-color;
}

@define-mixin mx_DialogButton_hover {
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/structures/RoomView.js
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,7 @@ module.exports = React.createClass({
const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
const Loader = sdk.getComponent("elements.Spinner");
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");

if (!this.state.room) {
if (this.state.roomLoading || this.state.peekLoading) {
Expand Down Expand Up @@ -1587,6 +1588,11 @@ module.exports = React.createClass({
/>;
}

const showRoomUpgradeBar = (
this.state.room.shouldUpgradeToVersion() &&
this.state.room.userMayUpgradeRoom(MatrixClientPeg.get().credentials.userId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already approved the other PR in js-sdk, but we can use the userId set on the room already here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in change the method to be currentUserMayUpgradeRoom()? Could do, not sure it's worth the extra wrapper function though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I wouldn't necessarily wrap it, but don't feel strong either way.

);

let aux = null;
let hideCancel = false;
if (this.state.editingRoomSettings) {
Expand All @@ -1598,6 +1604,9 @@ module.exports = React.createClass({
} else if (this.state.searching) {
hideCancel = true; // has own cancel
aux = <SearchBar ref="search_bar" searchInProgress={this.state.searchInProgress} onCancelClick={this.onCancelSearchClick} onSearch={this.onSearch} />;
} else if (showRoomUpgradeBar) {
aux = <RoomUpgradeWarningBar room={this.state.room} />;
hideCancel = true;
} else if (this.state.showingPinned) {
hideCancel = true; // has own cancel
aux = <PinnedEventsPanel room={this.state.room} onCancelClick={this.onPinnedClick} />;
Expand Down
106 changes: 106 additions & 0 deletions src/components/views/dialogs/RoomUpgradeDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
Copyright 2018 New Vector 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 React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

export default React.createClass({
displayName: 'RoomUpgradeDialog',

propTypes: {
room: PropTypes.object.isRequired,
onFinished: PropTypes.func.isRequired,
},

componentWillMount: function() {
this._targetVersion = this.props.room.shouldUpgradeToVersion();
},

getInitialState: function() {
return {
busy: false,
};
},

_onCancelClick: function() {
this.props.onFinished(false);
},

_onUpgradeClick: function() {
this.setState({busy: true});
MatrixClientPeg.get().upgradeRoom(this.props.room.roomId, this._targetVersion).catch((err) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Failed to upgrade room', '', ErrorDialog, {
title: _t("Failed to upgrade room"),
description: ((err && err.message) ? err.message : _t("The room upgrade could not be completed")),
});
}).finally(() => {
this.setState({busy: false});
});
},

render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
const Spinner = sdk.getComponent('views.elements.Spinner');

let buttons;
if (this.state.busy) {
buttons = <Spinner />;
} else {
buttons = <DialogButtons
primaryButton={_t(
'Upgrade this room to version %(version)s',
{version: this._targetVersion},
)}
primaryButtonClass="danger"
hasCancel={true}
onPrimaryButtonClick={this._onUpgradeClick}
focus={this.props.focus}
onCancel={this._onCancelClick}
/>;
}

return (
<BaseDialog className="mx_RoomUpgradeDialog"
onFinished={this.onCancelled}
title={_t("Upgrade Room Version")}
contentId='mx_Dialog_content'
onFinished={this.props.onFinished}
hasCancel={true}
>
<p>
{_t(
"Upgrading this room requires closing down the current " +
"instance of the room and creating a new room it its place. " +
"To give room members the best possible experience, we will:",
)}
</p>
<ol>
<li>{_t("Create a new room with the same name, description and avatar")}</li>
<li>{_t("Update any local room aliases to point to the new room")}</li>
<li>{_t("Stop users from speaking in the old version of the room, and post a message advising users to move to the new room")}</li>
<li>{_t("Put a link back to the old room at the start of the new room so people can see old messages")}</li>
</ol>
{buttons}
</BaseDialog>
);
},
});
15 changes: 14 additions & 1 deletion src/components/views/rooms/RoomSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,11 @@ module.exports = React.createClass({
});
},

_onRoomUpgradeClick: function() {
const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: this.props.room});
},

_onRoomMemberMembership: function() {
// Update, since our banned user list may have changed
this.forceUpdate();
Expand Down Expand Up @@ -930,6 +935,13 @@ module.exports = React.createClass({
);
});

let roomUpgradeButton = null;
if (this.props.room.shouldUpgradeToVersion() && this.props.room.userMayUpgradeRoom(myUserId)) {
roomUpgradeButton = <AccessibleButton className="mx_RoomSettings_upgradeButton danger" onClick={this._onRoomUpgradeClick}>
{ _t("Upgrade room to version %(ver)s", {ver: this.props.room.shouldUpgradeToVersion()}) }
</AccessibleButton>;
}

return (
<div className="mx_RoomSettings">

Expand Down Expand Up @@ -1041,7 +1053,8 @@ module.exports = React.createClass({
<h3>{ _t('Advanced') }</h3>
<div className="mx_RoomSettings_settings">
{ _t('Internal room ID: ') } <code>{ this.props.room.roomId }</code><br />
{ _t('Room version number: ') } <code>{ this.props.room.getVersion() }</code>
{ _t('Room version number: ') } <code>{ this.props.room.getVersion() }</code><br />
{ roomUpgradeButton }
</div>
</div>
);
Expand Down
57 changes: 57 additions & 0 deletions src/components/views/rooms/RoomUpgradeWarningBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2018 New Vector 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 React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import Modal from '../../../Modal';

import { _t } from '../../../languageHandler';

module.exports = React.createClass({
displayName: 'RoomUpgradeWarningBar',

propTypes: {
room: PropTypes.object.isRequired,
},

onUpgradeClick: function() {
const RoomUpgradeDialog = sdk.getComponent('dialogs.RoomUpgradeDialog');
Modal.createTrackedDialog('Upgrade Room Version', '', RoomUpgradeDialog, {room: this.props.room});
},

render: function() {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
return (
<div className="mx_RoomUpgradeWarningBar">
<div className="mx_RoomUpgradeWarningBar_header">
{_t("There is a known vulnerability affecting this room.")}
</div>
<div className="mx_RoomUpgradeWarningBar_body">
{_t("This room version is vulnerable to malicious modification of room state.")}
</div>
<p className="mx_RoomUpgradeWarningBar_upgradelink">
<AccessibleButton onClick={this.onUpgradeClick}>
{_t("Click here to upgrade to the latest room version and ensure room integrity is protected.")}
</AccessibleButton>
</p>
<div className="mx_RoomUpgradeWarningBar_small">
{_t("Only room administrators will see this warning")}
</div>
</div>
);
},
});
14 changes: 14 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@
"Guests cannot join this room even if explicitly invited.": "Guests cannot join this room even if explicitly invited.",
"Click here to fix": "Click here to fix",
"To send events of type <eventType/>, you must be a": "To send events of type <eventType/>, you must be a",
"Upgrade room to version %(ver)s": "Upgrade room to version %(ver)s",
"Who can access this room?": "Who can access this room?",
"Only people who have been invited": "Only people who have been invited",
"Anyone who knows the room's link, apart from guests": "Anyone who knows the room's link, apart from guests",
Expand All @@ -546,6 +547,10 @@
"Internal room ID: ": "Internal room ID: ",
"Room version number: ": "Room version number: ",
"Add a topic": "Add a topic",
"There is a known vulnerability affecting this room.": "There is a known vulnerability affecting this room.",
"This room version is vulnerable to malicious modification of room state.": "This room version is vulnerable to malicious modification of room state.",
"Click here to upgrade to the latest room version and ensure room integrity is protected.": "Click here to upgrade to the latest room version and ensure room integrity is protected.",
"Only room administrators will see this warning": "Only room administrators will see this warning",
"Search…": "Search…",
"This Room": "This Room",
"All Rooms": "All Rooms",
Expand Down Expand Up @@ -864,6 +869,15 @@
"Ignore request": "Ignore request",
"Loading device info...": "Loading device info...",
"Encryption key request": "Encryption key request",
"Failed to upgrade room": "Failed to upgrade room",
"The room upgrade could not be completed": "The room upgrade could not be completed",
"Upgrade this room to version %(version)s": "Upgrade this room to version %(version)s",
"Upgrade Room Version": "Upgrade Room Version",
"Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:": "Upgrading this room requires closing down the current instance of the room and creating a new room it its place. To give room members the best possible experience, we will:",
"Create a new room with the same name, description and avatar": "Create a new room with the same name, description and avatar",
"Update any local room aliases to point to the new room": "Update any local room aliases to point to the new room",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
"Put a link back to the old room at the start of the new room so people can see old messages": "Put a link back to the old room at the start of the new room so people can see old messages",
"Sign out": "Sign out",
"Log out and remove encryption keys?": "Log out and remove encryption keys?",
"Clear Storage and Sign Out": "Clear Storage and Sign Out",
Expand Down
1 change: 1 addition & 0 deletions test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ export function mkStubRoom(roomId = null) {
getAccountData: () => null,
hasMembershipState: () => null,
getVersion: () => '1',
shouldUpgradeToVersion: () => null,
getMyMembership: () => "join",
currentState: {
getStateEvents: sinon.stub(),
Expand Down