2016-02-02 12:46:14 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 OpenMarket Ltd
|
2019-02-20 23:13:35 +00:00
|
|
|
Copyright 2018, 2019 New Vector Ltd
|
2016-02-02 12:46:14 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2019-12-26 18:52:57 +00:00
|
|
|
import EditableItemList from "../elements/EditableItemList";
|
2020-01-05 21:58:36 +00:00
|
|
|
import React, {createRef} from 'react';
|
2017-12-26 01:03:18 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2019-12-20 21:13:46 +00:00
|
|
|
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
2019-12-20 21:41:07 +00:00
|
|
|
import * as sdk from "../../../index";
|
2017-05-25 10:39:08 +00:00
|
|
|
import { _t } from '../../../languageHandler';
|
2019-01-26 03:53:38 +00:00
|
|
|
import Field from "../elements/Field";
|
2019-02-20 23:13:35 +00:00
|
|
|
import ErrorDialog from "../dialogs/ErrorDialog";
|
2019-12-26 18:52:57 +00:00
|
|
|
import AccessibleButton from "../elements/AccessibleButton";
|
2020-01-13 20:28:33 +00:00
|
|
|
import Modal from "../../../Modal";
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-12-26 18:52:57 +00:00
|
|
|
class EditableAliasesList extends EditableItemList {
|
2020-01-05 21:58:36 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this._aliasField = createRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
_onAliasAdded = async () => {
|
|
|
|
await this._aliasField.current.validate({ allowEmpty: false });
|
|
|
|
|
|
|
|
if (this._aliasField.current.isValid) {
|
|
|
|
if (this.props.onItemAdded) this.props.onItemAdded(this.props.newItem);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._aliasField.current.focus();
|
|
|
|
this._aliasField.current.validate({ allowEmpty: false, focused: true });
|
|
|
|
};
|
|
|
|
|
2019-12-26 18:52:57 +00:00
|
|
|
_renderNewItemField() {
|
2020-03-09 15:31:30 +00:00
|
|
|
// if we don't need the RoomAliasField,
|
|
|
|
// we don't need to overriden version of _renderNewItemField
|
|
|
|
if (!this.props.domain) {
|
|
|
|
return super._renderNewItemField();
|
|
|
|
}
|
2019-12-26 18:52:57 +00:00
|
|
|
const RoomAliasField = sdk.getComponent('views.elements.RoomAliasField');
|
|
|
|
const onChange = (alias) => this._onNewItemChanged({target: {value: alias}});
|
|
|
|
return (
|
2019-12-27 17:05:51 +00:00
|
|
|
<form
|
2020-01-05 21:58:36 +00:00
|
|
|
onSubmit={this._onAliasAdded}
|
2019-12-27 17:05:51 +00:00
|
|
|
autoComplete="off"
|
|
|
|
noValidate={true}
|
|
|
|
className="mx_EditableItemList_newItem"
|
|
|
|
>
|
2019-12-26 18:52:57 +00:00
|
|
|
<RoomAliasField
|
|
|
|
id={`mx_EditableItemList_new_${this.props.id}`}
|
2020-01-05 21:58:36 +00:00
|
|
|
ref={this._aliasField}
|
2019-12-26 18:52:57 +00:00
|
|
|
onChange={onChange}
|
|
|
|
value={this.props.newItem || ""}
|
|
|
|
domain={this.props.domain} />
|
2020-01-05 21:58:36 +00:00
|
|
|
<AccessibleButton onClick={this._onAliasAdded} kind="primary">
|
2019-12-27 17:05:51 +00:00
|
|
|
{ _t("Add") }
|
2019-12-26 18:52:57 +00:00
|
|
|
</AccessibleButton>
|
|
|
|
</form>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
export default class AliasSettings extends React.Component {
|
|
|
|
static propTypes = {
|
2017-12-26 01:03:18 +00:00
|
|
|
roomId: PropTypes.string.isRequired,
|
|
|
|
canSetCanonicalAlias: PropTypes.bool.isRequired,
|
|
|
|
canSetAliases: PropTypes.bool.isRequired,
|
|
|
|
canonicalAliasEvent: PropTypes.object, // MatrixEvent
|
2019-02-20 23:13:35 +00:00
|
|
|
};
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
static defaultProps = {
|
|
|
|
canSetAliases: false,
|
|
|
|
canSetCanonicalAlias: false,
|
|
|
|
aliasEvents: [],
|
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2017-10-11 16:56:17 +00:00
|
|
|
const state = {
|
2020-03-09 15:26:43 +00:00
|
|
|
altAliases: [], // [ #alias:domain.tld, ... ]
|
|
|
|
localAliases: [], // [ #alias:my-hs.tld, ... ]
|
|
|
|
canonicalAlias: null, // #canonical:domain.tld
|
2019-02-21 23:11:09 +00:00
|
|
|
updatingCanonicalAlias: false,
|
2020-03-09 15:26:43 +00:00
|
|
|
localAliasesLoading: false,
|
2016-02-02 12:46:14 +00:00
|
|
|
};
|
|
|
|
|
2019-02-21 23:27:49 +00:00
|
|
|
if (props.canonicalAliasEvent) {
|
2020-03-09 15:26:43 +00:00
|
|
|
const content = props.canonicalAliasEvent.getContent();
|
|
|
|
const altAliases = content.alt_aliases;
|
|
|
|
if (Array.isArray(altAliases)) {
|
|
|
|
state.altAliases = altAliases.slice();
|
|
|
|
}
|
|
|
|
state.canonicalAlias = content.alias;
|
2016-09-16 17:01:14 +00:00
|
|
|
}
|
2018-09-20 00:07:01 +00:00
|
|
|
|
2019-02-21 23:27:49 +00:00
|
|
|
this.state = state;
|
2019-02-20 23:13:35 +00:00
|
|
|
}
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2020-03-09 15:26:43 +00:00
|
|
|
componentDidMount() {
|
|
|
|
return this.loadLocalAliases();
|
|
|
|
}
|
|
|
|
|
|
|
|
async loadLocalAliases() {
|
|
|
|
this.setState({ localAliasesLoading: true });
|
2020-02-19 14:15:05 +00:00
|
|
|
try {
|
2020-03-09 15:26:43 +00:00
|
|
|
const cli = MatrixClientPeg.get();
|
|
|
|
let localAliases = [];
|
2020-02-19 14:15:05 +00:00
|
|
|
if (await cli.doesServerSupportUnstableFeature("org.matrix.msc2432")) {
|
|
|
|
const response = await cli.unstableGetLocalAliases(this.props.roomId);
|
2020-03-09 15:26:43 +00:00
|
|
|
if (Array.isArray(response.aliases)) {
|
|
|
|
localAliases = response.aliases;
|
|
|
|
}
|
2020-02-19 14:15:05 +00:00
|
|
|
}
|
2020-03-09 15:26:43 +00:00
|
|
|
this.setState({ localAliases });
|
2020-02-19 14:15:05 +00:00
|
|
|
} finally {
|
2020-03-09 15:26:43 +00:00
|
|
|
this.setState({ localAliasesLoading: false });
|
2020-02-18 14:57:17 +00:00
|
|
|
}
|
2019-02-20 23:13:35 +00:00
|
|
|
}
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-02-21 23:11:09 +00:00
|
|
|
changeCanonicalAlias(alias) {
|
|
|
|
if (!this.props.canSetCanonicalAlias) return;
|
|
|
|
|
2020-03-09 15:26:43 +00:00
|
|
|
const oldAlias = this.state.canonicalAlias;
|
2019-02-21 23:11:09 +00:00
|
|
|
this.setState({
|
|
|
|
canonicalAlias: alias,
|
|
|
|
updatingCanonicalAlias: true,
|
|
|
|
});
|
|
|
|
|
2020-03-09 15:26:43 +00:00
|
|
|
const eventContent = {
|
|
|
|
alt_aliases: this.state.altAliases,
|
|
|
|
};
|
|
|
|
|
2019-02-21 23:11:09 +00:00
|
|
|
if (alias) eventContent["alias"] = alias;
|
|
|
|
|
|
|
|
MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.canonical_alias",
|
|
|
|
eventContent, "").catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
Modal.createTrackedDialog('Error updating main address', '', ErrorDialog, {
|
|
|
|
title: _t("Error updating main address"),
|
|
|
|
description: _t(
|
|
|
|
"There was an error updating the room's main address. It may not be allowed by the server " +
|
2019-02-22 00:53:29 +00:00
|
|
|
"or a temporary failure occurred.",
|
2019-02-21 23:11:09 +00:00
|
|
|
),
|
|
|
|
});
|
2020-03-09 15:26:43 +00:00
|
|
|
this.setState({canonicalAlias: oldAlias});
|
2019-02-21 23:11:09 +00:00
|
|
|
}).finally(() => {
|
|
|
|
this.setState({updatingCanonicalAlias: false});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-03-09 15:29:04 +00:00
|
|
|
changeAltAliases(altAliases) {
|
|
|
|
if (!this.props.canSetCanonicalAlias) return;
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
updatingCanonicalAlias: true,
|
|
|
|
altAliases,
|
|
|
|
});
|
|
|
|
|
|
|
|
const eventContent = {};
|
|
|
|
|
|
|
|
if (this.state.canonicalAlias) {
|
|
|
|
eventContent.alias = this.state.canonicalAlias;
|
|
|
|
}
|
|
|
|
if (altAliases) {
|
|
|
|
eventContent["alt_aliases"] = altAliases;
|
|
|
|
}
|
|
|
|
|
|
|
|
MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.canonical_alias",
|
|
|
|
eventContent, "").catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
Modal.createTrackedDialog('Error updating alternative addresses', '', ErrorDialog, {
|
|
|
|
title: _t("Error updating main address"),
|
|
|
|
description: _t(
|
|
|
|
"There was an error updating the room's alternative addresses. It may not be allowed by the server " +
|
|
|
|
"or a temporary failure occurred.",
|
|
|
|
),
|
|
|
|
});
|
|
|
|
}).finally(() => {
|
|
|
|
this.setState({updatingCanonicalAlias: false});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
onNewAliasChanged = (value) => {
|
2017-10-04 09:00:01 +00:00
|
|
|
this.setState({newAlias: value});
|
2019-02-20 23:13:35 +00:00
|
|
|
};
|
2017-10-04 09:00:01 +00:00
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
onLocalAliasAdded = (alias) => {
|
2016-02-02 12:46:14 +00:00
|
|
|
if (!alias || alias.length === 0) return; // ignore attempts to create blank aliases
|
|
|
|
|
2017-10-04 09:00:01 +00:00
|
|
|
const localDomain = MatrixClientPeg.get().getDomain();
|
2018-09-20 00:38:25 +00:00
|
|
|
if (!alias.includes(':')) alias += ':' + localDomain;
|
2020-01-05 21:58:36 +00:00
|
|
|
|
|
|
|
MatrixClientPeg.get().createAlias(alias, this.props.roomId).then(() => {
|
|
|
|
this.setState({
|
2020-03-09 15:26:43 +00:00
|
|
|
localAliases: this.state.localAliases.concat(alias),
|
|
|
|
newAlias: null,
|
2016-02-02 12:46:14 +00:00
|
|
|
});
|
2020-01-05 21:58:36 +00:00
|
|
|
if (!this.state.canonicalAlias) {
|
|
|
|
this.changeCanonicalAlias(alias);
|
|
|
|
}
|
|
|
|
}).catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
Modal.createTrackedDialog('Error creating alias', '', ErrorDialog, {
|
|
|
|
title: _t("Error creating alias"),
|
|
|
|
description: _t(
|
|
|
|
"There was an error creating that alias. It may not be allowed by the server " +
|
|
|
|
"or a temporary failure occurred.",
|
|
|
|
),
|
2016-02-02 12:46:14 +00:00
|
|
|
});
|
2020-01-05 21:58:36 +00:00
|
|
|
});
|
2019-02-20 23:13:35 +00:00
|
|
|
};
|
2018-09-20 00:07:01 +00:00
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
onLocalAliasDeleted = (index) => {
|
2020-03-09 15:26:43 +00:00
|
|
|
const alias = this.state.localAliases[index];
|
2019-02-21 03:44:08 +00:00
|
|
|
// TODO: In future, we should probably be making sure that the alias actually belongs
|
|
|
|
// to this room. See https://github.com/vector-im/riot-web/issues/7353
|
|
|
|
MatrixClientPeg.get().deleteAlias(alias).then(() => {
|
2020-03-09 15:26:43 +00:00
|
|
|
const localAliases = this.state.localAliases.slice();
|
|
|
|
localAliases.splice(index);
|
|
|
|
this.setState({localAliases});
|
2019-02-21 23:11:09 +00:00
|
|
|
|
|
|
|
if (this.state.canonicalAlias === alias) {
|
|
|
|
this.changeCanonicalAlias(null);
|
2019-02-21 03:44:08 +00:00
|
|
|
}
|
|
|
|
}).catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
Modal.createTrackedDialog('Error removing alias', '', ErrorDialog, {
|
|
|
|
title: _t("Error removing alias"),
|
|
|
|
description: _t(
|
|
|
|
"There was an error removing that alias. It may no longer exist or a temporary " +
|
2019-02-22 00:53:29 +00:00
|
|
|
"error occurred.",
|
2019-02-21 03:44:08 +00:00
|
|
|
),
|
2018-09-20 00:07:01 +00:00
|
|
|
});
|
2019-02-21 03:44:08 +00:00
|
|
|
});
|
2019-02-20 23:13:35 +00:00
|
|
|
};
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
onCanonicalAliasChange = (event) => {
|
2019-02-21 23:11:09 +00:00
|
|
|
this.changeCanonicalAlias(event.target.value);
|
2019-02-20 23:13:35 +00:00
|
|
|
};
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2020-03-09 15:29:04 +00:00
|
|
|
onNewAltAliasChanged = (value) => {
|
|
|
|
this.setState({newAltAlias: value});
|
|
|
|
}
|
|
|
|
|
|
|
|
onAltAliasAdded = (alias) => {
|
|
|
|
const altAliases = this.state.altAliases.slice();
|
|
|
|
if (!altAliases.some(a => a.trim() === alias.trim())) {
|
|
|
|
altAliases.push(alias.trim());
|
|
|
|
this.changeAltAliases(altAliases);
|
|
|
|
this.setState({newAltAlias: ""});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onAltAliasDeleted = (index) => {
|
|
|
|
const altAliases = this.state.altAliases.slice();
|
|
|
|
altAliases.splice(index, 1);
|
|
|
|
this.changeAltAliases(altAliases);
|
|
|
|
}
|
|
|
|
|
2020-03-09 15:26:43 +00:00
|
|
|
_getAliases() {
|
|
|
|
return this.state.altAliases.concat(this._getLocalNonAltAliases());
|
|
|
|
}
|
|
|
|
|
|
|
|
_getLocalNonAltAliases() {
|
|
|
|
const {altAliases} = this.state;
|
|
|
|
return this.state.localAliases.filter(alias => !altAliases.includes(alias));
|
|
|
|
}
|
|
|
|
|
2019-02-20 23:13:35 +00:00
|
|
|
render() {
|
2017-10-11 16:56:17 +00:00
|
|
|
const localDomain = MatrixClientPeg.get().getDomain();
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2019-02-21 23:33:02 +00:00
|
|
|
let found = false;
|
|
|
|
const canonicalValue = this.state.canonicalAlias || "";
|
|
|
|
const canonicalAliasSection = (
|
|
|
|
<Field onChange={this.onCanonicalAliasChange} value={canonicalValue}
|
|
|
|
disabled={this.state.updatingCanonicalAlias || !this.props.canSetCanonicalAlias}
|
|
|
|
element='select' id='canonicalAlias' label={_t('Main address')}>
|
|
|
|
<option value="" key="unset">{ _t('not specified') }</option>
|
|
|
|
{
|
2020-03-09 15:26:43 +00:00
|
|
|
this._getAliases().map((alias, i) => {
|
|
|
|
if (alias === this.state.canonicalAlias) found = true;
|
|
|
|
return (
|
|
|
|
<option value={alias} key={i}>
|
|
|
|
{ alias }
|
|
|
|
</option>
|
|
|
|
);
|
2019-02-21 23:33:02 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
{
|
|
|
|
found || !this.state.canonicalAlias ? '' :
|
|
|
|
<option value={ this.state.canonicalAlias } key='arbitrary'>
|
|
|
|
{ this.state.canonicalAlias }
|
|
|
|
</option>
|
|
|
|
}
|
|
|
|
</Field>
|
|
|
|
);
|
2016-02-02 12:46:14 +00:00
|
|
|
|
2020-02-19 14:15:05 +00:00
|
|
|
let localAliasesList;
|
|
|
|
if (this.state.localAliasesLoading) {
|
|
|
|
const Spinner = sdk.getComponent("elements.Spinner");
|
|
|
|
localAliasesList = <Spinner />;
|
|
|
|
} else {
|
2020-03-09 15:26:43 +00:00
|
|
|
localAliasesList = (<EditableAliasesList
|
2020-02-19 14:15:05 +00:00
|
|
|
id="roomAliases"
|
|
|
|
className={"mx_RoomSettings_localAliases"}
|
2020-03-09 15:26:43 +00:00
|
|
|
items={this.state.localAliases}
|
2020-02-19 14:15:05 +00:00
|
|
|
newItem={this.state.newAlias}
|
|
|
|
onNewItemChanged={this.onNewAliasChanged}
|
|
|
|
canRemove={this.props.canSetAliases}
|
|
|
|
canEdit={this.props.canSetAliases}
|
|
|
|
onItemAdded={this.onLocalAliasAdded}
|
|
|
|
onItemRemoved={this.onLocalAliasDeleted}
|
|
|
|
noItemsLabel={_t('This room has no local addresses')}
|
|
|
|
placeholder={_t(
|
|
|
|
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
|
|
|
|
)}
|
|
|
|
domain={localDomain}
|
2020-03-09 15:26:43 +00:00
|
|
|
/>);
|
2020-02-19 14:15:05 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 12:46:14 +00:00
|
|
|
return (
|
2019-01-28 18:34:21 +00:00
|
|
|
<div className='mx_AliasSettings'>
|
2019-02-21 03:44:08 +00:00
|
|
|
{canonicalAliasSection}
|
2020-03-09 15:31:07 +00:00
|
|
|
<datalist id="mx_AliasSettings_altRecommendations">
|
|
|
|
{this._getLocalNonAltAliases().map(alias => {
|
|
|
|
return <option value={alias} key={alias} />;
|
|
|
|
})};
|
|
|
|
</datalist>
|
2020-03-09 15:29:04 +00:00
|
|
|
<EditableAliasesList
|
|
|
|
id="roomAltAliases"
|
|
|
|
className={"mx_RoomSettings_altAliases"}
|
|
|
|
items={this.state.altAliases}
|
|
|
|
newItem={this.state.newAltAlias}
|
|
|
|
onNewItemChanged={this.onNewAltAliasChanged}
|
|
|
|
canRemove={this.props.canSetCanonicalAlias}
|
|
|
|
canEdit={this.props.canSetCanonicalAlias}
|
|
|
|
onItemAdded={this.onAltAliasAdded}
|
|
|
|
onItemRemoved={this.onAltAliasDeleted}
|
2020-03-09 15:31:07 +00:00
|
|
|
suggestionsListId="mx_AliasSettings_altRecommendations"
|
2020-03-09 15:29:04 +00:00
|
|
|
itemsLabel={_t('Alternative addresses for this room:')}
|
|
|
|
noItemsLabel={_t('This room has no alternative addresses')}
|
|
|
|
placeholder={_t(
|
|
|
|
'New address (e.g. #foo:domain)',
|
|
|
|
)}
|
|
|
|
/>
|
2020-03-09 15:32:13 +00:00
|
|
|
<details>
|
|
|
|
<summary>{_t('Local addresses (unmoderated content)')}</summary>
|
|
|
|
{localAliasesList}
|
|
|
|
</details>
|
2016-02-02 12:46:14 +00:00
|
|
|
</div>
|
|
|
|
);
|
2019-02-20 23:13:35 +00:00
|
|
|
}
|
2019-02-22 01:18:12 +00:00
|
|
|
}
|