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

Notify users about denied access on ask to join rooms #11479

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
798f13a
Allow setting knock room visibility
Aug 21, 2023
77e62b9
Merge remote-tracking branch 'origin/develop' into develop
nurjinjafar Aug 25, 2023
5bdc050
Merge branch 'develop' of https://github.com/nordeck/matrix-react-sdk…
nurjinjafar Aug 28, 2023
4c3b352
refactor / fix deny requests isues
nurjinjafar Aug 28, 2023
fe0a3d9
fix tests create denied message test
ahmadkadri Aug 28, 2023
870e0d8
add another test for the primary action for denied request
ahmadkadri Aug 29, 2023
35e3697
Merge branch 'develop' of https://github.com/nordeck/matrix-react-sdk…
nurjinjafar Aug 29, 2023
2b03d62
add translation and fix linter issues
nurjinjafar Aug 29, 2023
8ba8774
refactor / fix deny requests issues
nurjinjafar Aug 28, 2023
1d26173
fix tests create denied message test
ahmadkadri Aug 28, 2023
a66695f
add another test for the primary action for denied request
ahmadkadri Aug 29, 2023
ef62124
Update react-types (#10762)
renovate[bot] Aug 25, 2023
b01a1ef
Fix avatar defects (#11473)
Aug 29, 2023
abddfe6
Upgrade matrix-js-sdk to 28.0.0-rc.1
RiotRobot Aug 22, 2023
4f5f7bd
Prepare changelog for v3.79.0-rc.1
RiotRobot Aug 22, 2023
3a51821
v3.79.0-rc.1
RiotRobot Aug 22, 2023
0f72946
Prepare changelog for v3.79.0-rc.2
RiotRobot Aug 23, 2023
2321777
v3.79.0-rc.2
RiotRobot Aug 23, 2023
6c65198
Upgrade matrix-js-sdk to 28.0.0
RiotRobot Aug 29, 2023
2d3314f
Prepare changelog for v3.79.0
RiotRobot Aug 29, 2023
5090b5e
v3.79.0
RiotRobot Aug 29, 2023
3b95f59
Resetting package fields for development
RiotRobot Aug 29, 2023
a3dcc95
Reset matrix-js-sdk back to develop branch
RiotRobot Aug 29, 2023
3987100
add translation and fix linter issues
nurjinjafar Aug 29, 2023
d7324ee
Merge remote-tracking branch 'origin/nurjinjafar/notify_users_about_d…
nurjinjafar Aug 29, 2023
ae926b2
Merge branch 'develop' of https://github.com/nordeck/matrix-react-sdk…
nurjinjafar Aug 29, 2023
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
5 changes: 5 additions & 0 deletions res/css/views/dialogs/_CreateRoomDialog.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,8 @@ limitations under the License.
font-size: $font-12px;
}
}

.mx_CreateRoomDialog_labelledCheckbox {
color: $muted-fg-color;
margin-top: var(--cpd-space-6x);
}
5 changes: 5 additions & 0 deletions res/css/views/settings/_JoinRuleSettings.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,8 @@ limitations under the License.
}
}
}

.mx_JoinRuleSettings_labelledCheckbox {
font: var(--cpd-font-body-md-regular);
margin-top: var(--cpd-space-2x);
}
1 change: 1 addition & 0 deletions src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
knocked={myMembership === "knock" || this.state.knocked}
onSubmitAskToJoin={this.onSubmitAskToJoin}
onCancelAskToJoin={this.onCancelAskToJoin}
onForgetClick={this.onForgetClick}
/>
</ErrorBoundary>
</div>
Expand Down
19 changes: 19 additions & 0 deletions src/components/views/dialogs/CreateRoomDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { privateShouldBeEncrypted } from "../../../utils/rooms";
import SettingsStore from "../../../settings/SettingsStore";
import LabelledCheckbox from "../elements/LabelledCheckbox";

interface IProps {
type?: RoomType;
Expand Down Expand Up @@ -129,6 +130,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {

if (this.state.joinRule === JoinRule.Knock) {
opts.joinRule = JoinRule.Knock;
createOpts.visibility = this.state.isPublic ? Visibility.Public : Visibility.Private;
}

return opts;
Expand Down Expand Up @@ -215,6 +217,10 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
return result;
};

private onIsPublicChange = (isPublic: boolean): void => {
this.setState({ isPublic });
};

private static validateRoomName = withValidation({
rules: [
{
Expand Down Expand Up @@ -298,6 +304,18 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
);
}

let visibilitySection: JSX.Element | undefined;
if (this.state.joinRule === JoinRule.Knock) {
visibilitySection = (
<LabelledCheckbox
className="mx_CreateRoomDialog_labelledCheckbox"
label={_t("Make this room visible in the public room directory.")}
onChange={this.onIsPublicChange}
value={this.state.isPublic}
/>
);
}

let e2eeSection: JSX.Element | undefined;
if (this.state.joinRule !== JoinRule.Public) {
let microcopy: string;
Expand Down Expand Up @@ -383,6 +401,7 @@ export default class CreateRoomDialog extends React.Component<IProps, IState> {
/>

{publicPrivateLabel}
{visibilitySection}
{e2eeSection}
{aliasField}
<details onToggle={this.onDetailsToggled} className="mx_CreateRoomDialog_details">
Expand Down
36 changes: 32 additions & 4 deletions src/components/views/dialogs/spotlight/SpotlightDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
RoomType,
Room,
HierarchyRoom,
JoinRule,
} from "matrix-js-sdk/src/matrix";
import { normalize } from "matrix-js-sdk/src/utils";
import React, { ChangeEvent, RefObject, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
Expand Down Expand Up @@ -276,6 +277,10 @@ const roomAriaUnreadLabel = (room: Room, notification: RoomNotificationState): s
}
};

const canAskToJoin = (joinRule?: JoinRule): boolean => {
return SettingsStore.getValue("feature_ask_to_join") && JoinRule.Knock === joinRule;
};

interface IDirectoryOpts {
limit: number;
query: string;
Expand Down Expand Up @@ -514,7 +519,14 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
}, [results, filter]);

const viewRoom = (
room: { roomId: string; roomAlias?: string; autoJoin?: boolean; shouldPeek?: boolean; viaServers?: string[] },
room: {
roomId: string;
roomAlias?: string;
autoJoin?: boolean;
shouldPeek?: boolean;
viaServers?: string[];
joinRule?: IPublicRoomsChunkRoom["join_rule"];
},
persist = false,
viaKeyboard = false,
): void => {
Expand All @@ -538,10 +550,15 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
metricsViaKeyboard: viaKeyboard,
room_id: room.roomId,
room_alias: room.roomAlias,
auto_join: room.autoJoin,
auto_join: room.autoJoin && !canAskToJoin(room.joinRule),
should_peek: room.shouldPeek,
via_servers: room.viaServers,
});

if (canAskToJoin(room.joinRule)) {
defaultDispatcher.dispatch({ action: Action.PromptAskToJoin });
}

onFinished();
};

Expand Down Expand Up @@ -647,12 +664,15 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
}
if (isPublicRoomResult(result)) {
const clientRoom = cli.getRoom(result.publicRoom.room_id);
const joinRule = result.publicRoom.join_rule;
// Element Web currently does not allow guests to join rooms, so we
// instead show them view buttons for all rooms. If the room is not
// world readable, a modal will appear asking you to register first. If
// it is readable, the preview appears as normal.
const showViewButton =
clientRoom?.getMyMembership() === "join" || result.publicRoom.world_readable || cli.isGuest();
clientRoom?.getMyMembership() === "join" ||
(result.publicRoom.world_readable && !canAskToJoin(joinRule)) ||
cli.isGuest();

const listener = (ev: ButtonEvent): void => {
ev.stopPropagation();
Expand All @@ -665,12 +685,20 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
autoJoin: !result.publicRoom.world_readable && !cli.isGuest(),
shouldPeek: result.publicRoom.world_readable || cli.isGuest(),
viaServers: config ? [config.roomServer] : undefined,
joinRule,
},
true,
ev.type !== "click",
);
};

let buttonLabel;
if (showViewButton) {
buttonLabel = _t("action|view");
} else {
buttonLabel = canAskToJoin(joinRule) ? _t("action|ask_to_join") : _t("action|join");
}

return (
<Option
id={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}`}
Expand All @@ -683,7 +711,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
onClick={listener}
tabIndex={-1}
>
{showViewButton ? _t("action|view") : _t("action|join")}
{buttonLabel}
</AccessibleButton>
}
aria-labelledby={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}_name`}
Expand Down
7 changes: 5 additions & 2 deletions src/components/views/elements/LabelledCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/

import React from "react";
import classnames from "classnames";

import StyledCheckbox from "./StyledCheckbox";

Expand All @@ -29,11 +30,13 @@ interface IProps {
disabled?: boolean;
// The function to call when the value changes
onChange(checked: boolean): void;
// Optional CSS class to apply to the label
className?: string;
}

const LabelledCheckbox: React.FC<IProps> = ({ value, label, byline, disabled, onChange }) => {
const LabelledCheckbox: React.FC<IProps> = ({ value, label, byline, disabled, onChange, className }) => {
return (
<label className="mx_LabelledCheckbox">
<label className={classnames("mx_LabelledCheckbox", className)}>
<StyledCheckbox disabled={disabled} checked={value} onChange={(e) => onChange(e.target.checked)} />
<div className="mx_LabelledCheckbox_labels">
<span className="mx_LabelledCheckbox_label">{label}</span>
Expand Down
20 changes: 20 additions & 0 deletions src/components/views/rooms/RoomPreviewBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum MessageCase {
OtherError = "OtherError",
PromptAskToJoin = "PromptAskToJoin",
Knocked = "Knocked",
RequestDenied = "requestDenied",
}

interface IProps {
Expand Down Expand Up @@ -188,7 +189,11 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
const myMember = this.getMyMember();

if (myMember) {
const previousMembership = myMember.events.member?.event?.unsigned?.prev_content?.membership;
if (myMember.isKicked()) {
if (previousMembership === "knock") {
return MessageCase.RequestDenied;
}
return MessageCase.Kicked;
} else if (myMember.membership === "ban") {
return MessageCase.Banned;
Expand Down Expand Up @@ -397,6 +402,21 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
}
break;
}
case MessageCase.RequestDenied: {
title = _t("You have been denied access");

subTitle = _t(
"As you have been denied access, please wait for an invitation from a room admin or moderator.",
);

if (isSpace) {
primaryActionLabel = _t("Forget this space");
} else {
primaryActionLabel = _t("Forget this room");
}
primaryActionHandler = this.props.onForgetClick;
break;
}
case MessageCase.Banned: {
const { memberName, reason } = this.getKickOrBanInfo();
if (roomName) {
Expand Down
46 changes: 43 additions & 3 deletions src/components/views/settings/JoinRuleSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { ReactNode } from "react";
import { IJoinRuleEventContent, JoinRule, RestrictedAllowType, Room, EventType } from "matrix-js-sdk/src/matrix";
import React, { ReactNode, useEffect, useState } from "react";
import {
IJoinRuleEventContent,
JoinRule,
RestrictedAllowType,
Room,
EventType,
Visibility,
} from "matrix-js-sdk/src/matrix";

import StyledRadioGroup, { IDefinition } from "../elements/StyledRadioGroup";
import { _t } from "../../../languageHandler";
Expand All @@ -34,6 +41,7 @@ import { Action } from "../../../dispatcher/actions";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { doesRoomVersionSupport, PreferredRoomVersions } from "../../../utils/PreferredRoomVersions";
import SettingsStore from "../../../settings/SettingsStore";
import LabelledCheckbox from "../elements/LabelledCheckbox";

export interface JoinRuleSettingsProps {
room: Room;
Expand Down Expand Up @@ -76,6 +84,23 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
? content?.allow?.filter((o) => o.type === RestrictedAllowType.RoomMembership).map((o) => o.room_id)
: undefined;

const [visibility, setVisibility] = useState(Visibility.Private);

useEffect(() => {
if (joinRule === JoinRule.Knock) {
cli.getRoomDirectoryVisibility(room.roomId)
.then(({ visibility }) => setVisibility(visibility))
.catch(onError);
}
}, [cli, joinRule, onError, room.roomId]);

const onVisibilityChange = (checked: boolean): void => {
const visibility = checked ? Visibility.Public : Visibility.Private;
cli.setRoomDirectoryVisibility(room.roomId, visibility)
.then(() => setVisibility(visibility))
.catch(onError);
};

const editRestrictedRoomIds = async (): Promise<string[] | undefined> => {
let selected = restrictedAllowRoomIds;
if (!selected?.length && SpaceStore.instance.activeSpaceRoom) {
Expand Down Expand Up @@ -297,7 +322,22 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
{preferredKnockVersion && upgradeRequiredPill}
</>
),
description: _t("People cannot join unless access is granted."),
description: (
<>
{_t("People cannot join unless access is granted.")}
<LabelledCheckbox
className="mx_JoinRuleSettings_labelledCheckbox"
disabled={!!preferredKnockVersion || joinRule !== JoinRule.Knock}
label={
room.isSpaceRoom()
? _t("Make this space visible in the public room directory.")
: _t("Make this room visible in the public room directory.")
}
onChange={onVisibilityChange}
value={visibility === Visibility.Public}
/>
</>
),
});
}

Expand Down
5 changes: 5 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"resend": "Resend",
"next": "Next",
"view": "View",
"ask_to_join": "Ask to join",
"forward": "Forward",
"copy_link": "Copy link",
"logout": "Logout",
Expand Down Expand Up @@ -1199,6 +1200,8 @@
"Space members": "Space members",
"Ask to join": "Ask to join",
"People cannot join unless access is granted.": "People cannot join unless access is granted.",
"Make this space visible in the public room directory.": "Make this space visible in the public room directory.",
"Make this room visible in the public room directory.": "Make this room visible in the public room directory.",
"This room is in some spaces you're not an admin of. In those spaces, the old room will still be shown, but people will be prompted to join the new one.": "This room is in some spaces you're not an admin of. In those spaces, the old room will still be shown, but people will be prompted to join the new one.",
"This upgrade will allow members of selected spaces access to this room without an invite.": "This upgrade will allow members of selected spaces access to this room without an invite.",
"IRC (Experimental)": "IRC (Experimental)",
Expand Down Expand Up @@ -1869,6 +1872,8 @@
"Join the conversation with an account": "Join the conversation with an account",
"Sign Up": "Sign Up",
"Loading preview": "Loading preview",
"You have been denied access": "You have been denied access",
"As you have been denied access, please wait for an invitation from a room admin or moderator.": "As you have been denied access, please wait for an invitation from a room admin or moderator.",
"You were removed from %(roomName)s by %(memberName)s": "You were removed from %(roomName)s by %(memberName)s",
"You were removed by %(memberName)s": "You were removed by %(memberName)s",
"Reason: %(reason)s": "Reason: %(reason)s",
Expand Down
Loading
Loading