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

Fix rejoin of knock rooms #11980

Merged
merged 3 commits into from
Dec 4, 2023
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
120 changes: 119 additions & 1 deletion cypress/e2e/knock/knock-into-room.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe("Knock Into Room", () => {
cy.stopHomeserver(homeserver);
});

it("should knock into the room then knock is approved and user joins the room", () => {
it("should knock into the room then knock is approved and user joins the room then user is kicked and joins again", () => {
cy.viewRoomById(roomId);

cy.get(".mx_RoomPreviewBar").within(() => {
Expand Down Expand Up @@ -104,6 +104,124 @@ describe("Knock Into Room", () => {
cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });

cy.findByText("Alice joined the room").should("exist");

cy.window().then(async (win) => {
// bot kicks Alice
await bot.kick(roomId, user.userId);
});

cy.get(".mx_RoomPreviewBar").within(() => {
cy.findByRole("button", { name: "Re-join" }).click();

cy.findByRole("heading", { name: "Ask to join Cybersecurity?" });
cy.findByRole("button", { name: "Request access" }).click();
});

cy.window().then(async (win) => {
// bot waits for knock request from Alice
await waitForRoom(win, bot, roomId, (room) => {
const events = room.getLiveTimeline().getEvents();
return events.some(
(e) =>
e.getType() === "m.room.member" &&
e.getContent()?.membership === "knock" &&
e.getContent()?.displayname === "Alice",
);
});

// bot invites Alice
await bot.invite(roomId, user.userId);
});

// Alice have to accept invitation in order to join the room.
// It will be not needed when homeserver implements auto accept knock requests.
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();

cy.findByText("Alice was invited, joined, was removed, was invited, and joined").should("exist");
});

it("should knock into the room then knock is approved and user joins the room then user is banned/unbanned and joins again", () => {
cy.viewRoomById(roomId);

cy.get(".mx_RoomPreviewBar").within(() => {
cy.findByRole("button", { name: "Join the discussion" }).click();

cy.findByRole("heading", { name: "Ask to join?" });
cy.findByRole("textbox");
cy.findByRole("button", { name: "Request access" }).click();

cy.findByRole("heading", { name: "Request to join sent" });
});

// Knocked room should appear in Rooms
cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });

cy.window().then(async (win) => {
// bot waits for knock request from Alice
await waitForRoom(win, bot, roomId, (room) => {
const events = room.getLiveTimeline().getEvents();
return events.some(
(e) =>
e.getType() === "m.room.member" &&
e.getContent()?.membership === "knock" &&
e.getContent()?.displayname === "Alice",
);
});

// bot invites Alice
await bot.invite(roomId, user.userId);
});

cy.findByRole("group", { name: "Invites" }).findByRole("treeitem", { name: "Cybersecurity" });

// Alice have to accept invitation in order to join the room.
// It will be not needed when homeserver implements auto accept knock requests.
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();

cy.findByRole("group", { name: "Rooms" }).findByRole("treeitem", { name: "Cybersecurity" });

cy.findByText("Alice joined the room").should("exist");

cy.window().then(async (win) => {
// bot bans Alice
await bot.ban(roomId, user.userId);
});

cy.get(".mx_RoomPreviewBar").findByText("You were banned from Cybersecurity by Bob").should("exist");

cy.window().then(async (win) => {
// bot unbans Alice
await bot.unban(roomId, user.userId);
});

cy.get(".mx_RoomPreviewBar").within(() => {
cy.findByRole("button", { name: "Re-join" }).click();

cy.findByRole("heading", { name: "Ask to join Cybersecurity?" });
cy.findByRole("button", { name: "Request access" }).click();
});

cy.window().then(async (win) => {
// bot waits for knock request from Alice
await waitForRoom(win, bot, roomId, (room) => {
const events = room.getLiveTimeline().getEvents();
return events.some(
(e) =>
e.getType() === "m.room.member" &&
e.getContent()?.membership === "knock" &&
e.getContent()?.displayname === "Alice",
);
});

// bot invites Alice
await bot.invite(roomId, user.userId);
});

// Alice have to accept invitation in order to join the room.
// It will be not needed when homeserver implements auto accept knock requests.
cy.get(".mx_RoomView").findByRole("button", { name: "Accept" }).click();

cy.findByText("Alice was invited, joined, was banned, was unbanned, was invited, and joined").should("exist");
});

it("should knock into the room and knock is cancelled by user himself", () => {
Expand Down
4 changes: 3 additions & 1 deletion src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2229,8 +2229,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
<div className="mx_RoomView" data-room-header={roomHeaderType}>
<ErrorBoundary>
<RoomPreviewBar
onJoinClick={this.onJoinButtonClicked}
room={this.state.room}
promptAskToJoin={myMembership === "leave" || this.state.promptAskToJoin}
canAskToJoinAndMembershipIsLeave={myMembership === "leave"}
promptAskToJoin={this.state.promptAskToJoin}
knocked={myMembership === "knock"}
onSubmitAskToJoin={this.onSubmitAskToJoin}
onCancelAskToJoin={this.onCancelAskToJoin}
Expand Down
5 changes: 4 additions & 1 deletion src/components/views/rooms/RoomPreviewBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ interface IProps {
onRejectAndIgnoreClick?(): void;
onForgetClick?(): void;

canAskToJoinAndMembershipIsLeave?: boolean;
promptAskToJoin?: boolean;
knocked?: boolean;
onSubmitAskToJoin?(reason?: string): void;
Expand Down Expand Up @@ -193,6 +194,8 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
if (myMember.isKicked()) {
if (previousMembership === "knock") {
return MessageCase.RequestDenied;
} else if (this.props.promptAskToJoin) {
return MessageCase.PromptAskToJoin;
}
return MessageCase.Kicked;
} else if (myMember.membership === "ban") {
Expand All @@ -208,7 +211,7 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
return MessageCase.Loading;
} else if (this.props.knocked) {
return MessageCase.Knocked;
} else if (this.props.promptAskToJoin) {
} else if (this.props.canAskToJoinAndMembershipIsLeave || this.props.promptAskToJoin) {
return MessageCase.PromptAskToJoin;
}

Expand Down
10 changes: 9 additions & 1 deletion test/components/views/rooms/RoomPreviewBar-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ describe("<RoomPreviewBar />", () => {
it("renders kicked message", () => {
const room = createRoom(roomId, otherUserId);
jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ isKicked: true }));
const component = getComponent({ room, promptAskToJoin: true });
const component = getComponent({ room, canAskToJoinAndMembershipIsLeave: true, promptAskToJoin: false });

expect(getMessage(component)).toMatchSnapshot();
});
Expand Down Expand Up @@ -458,6 +458,14 @@ describe("<RoomPreviewBar />", () => {
expect(getMessage(component)).toMatchSnapshot();
});

it("renders the corresponding message when kicked", () => {
const room = createRoom(roomId, otherUserId);
jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ isKicked: true }));
const component = getComponent({ room, promptAskToJoin: true });

expect(getMessage(component)).toMatchSnapshot();
});

it("renders the corresponding message with a generic title", () => {
const component = render(<RoomPreviewBar promptAskToJoin />);
expect(getMessage(component)).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding mes
</div>
`;

exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message when kicked 1`] = `
<div
class="mx_RoomPreviewBar_message"
>
<h3>
Ask to join RoomPreviewBar-test-room?
</h3>
<p>
<span
class="_avatar_1o69u_17 mx_BaseAvatar _avatar-imageless_1o69u_60"
data-color="4"
data-testid="avatar-img"
data-type="round"
role="presentation"
style="--cpd-avatar-size: 36px;"
>
R
</span>
</p>
<p>
You need to be granted access to this room in order to view or participate in the conversation. You can send a request to join below.
</p>
</div>
`;

exports[`<RoomPreviewBar /> message case AskToJoin renders the corresponding message with a generic title 1`] = `
<div
class="mx_RoomPreviewBar_message"
Expand Down