From ce96853ad7bc96cabf60301cd3228a64b439ff8d Mon Sep 17 00:00:00 2001 From: nurjin jafar Date: Thu, 7 Sep 2023 10:07:43 +0200 Subject: [PATCH] Notify users about denied access on ask-to-join rooms (#11480) * Implement denied request mask and logic Signed-off-by: AHMAD KADRI <52747422+ahmadkadri@users.noreply.github.com> * refactor / fix deny requests isues * fix tests create denied message test Signed-off-by: AHMAD KADRI <52747422+ahmadkadri@users.noreply.github.com> * add another test for the primary action for denied request Signed-off-by: AHMAD KADRI <52747422+ahmadkadri@users.noreply.github.com> * fix linter issues Signed-off-by: nurjinn jafar * regenerate translation Signed-off-by: nurjinn jafar * fix translation and minor refactoring Signed-off-by: nurjinn jafar * segment into 4 * Remove parallel from Cypress command to avoid talking to Cypress Cloud * Re-add --parallel flag for Percy * Prevent event propagation when clicking icon buttons (#11515) * Prevent event propagation when clicking icon buttons * Inhibit view user on click behaviour for room header face pile * Update snapshot * Add a 'm.relates_to' to edits in receipt tests and disable failing tests (#11501) * Add a 'm.relates_to' to edits in receipt tests * Disable a test that fails with real edits * Wait for the room to be read after we mark it as read * Skip tests that are failing because of inconsistencies between local and CI behaviour * Allow creating public knock rooms (#11481) * Allow creating public knock rooms Signed-off-by: Charly Nguyen * Apply PR feedback Signed-off-by: Charly Nguyen * Apply PR feedback Signed-off-by: Charly Nguyen --------- Signed-off-by: Charly Nguyen * Collect `console.debug` logs during cypress tests (#11478) In order for the logs collected by cypress to actually be useful, we really need `cons:debug`. * Migrate more strings to translation keys (#11522) * Only show Search button in RoomSummaryCard if new room UI enabled (#11524) * Only show Search button in RoomSummaryCard if new room UI enabled * Update snapshot * Update vector-im (#11526) * Update vector-im * Update snapshots of Compound Avatars * Update snapshots of Compound Avatars --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * Migrate more strings to translation keys (#11530) * Fix regression around FacePile with overflow (#11527) * Work around compound-web AvatarStack not applying overlap to non-Avatars * Fix FacePile overflow tile not being layed out correctly * Use RoomStateEvent.Update for knocks (#11516) Signed-off-by: Charly Nguyen * Cypress tests for event shields (#11525) * Factor downloadKey out to `utils.ts` * Add a new `describe` block for event shields * create a beforeEach block * Cypress tests for event shields * Document how to match the CI config for Cypress (#11531) * Document how to match the CI config for Cypress * Clarify language about needing Chrome * Move Cypress info into the Cypress-specific docs * Migrate more strings to translation keys (#11532) --------- Signed-off-by: AHMAD KADRI <52747422+ahmadkadri@users.noreply.github.com> Signed-off-by: nurjinn jafar Signed-off-by: Charly Nguyen Co-authored-by: AHMAD KADRI <52747422+ahmadkadri@users.noreply.github.com> Co-authored-by: Kerry Archibald Co-authored-by: Andy Balaam Co-authored-by: Johannes Marbach Co-authored-by: Germain Co-authored-by: Charly Nguyen <1422657+charlynguyen@users.noreply.github.com> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- src/components/structures/RoomView.tsx | 1 + src/components/views/rooms/RoomPreviewBar.tsx | 20 +++++++++++++ src/i18n/strings/en_EN.json | 2 ++ .../views/rooms/RoomPreviewBar-test.tsx | 30 +++++++++++++++++-- .../RoomPreviewBar-test.tsx.snap | 13 ++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 59906c5a748..d1b569ccfa3 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2205,6 +2205,7 @@ export class RoomView extends React.Component { knocked={myMembership === "knock" || this.state.knocked} onSubmitAskToJoin={this.onSubmitAskToJoin} onCancelAskToJoin={this.onCancelAskToJoin} + onForgetClick={this.onForgetClick} /> diff --git a/src/components/views/rooms/RoomPreviewBar.tsx b/src/components/views/rooms/RoomPreviewBar.tsx index 5f610c344e6..ee1a9a69fb7 100644 --- a/src/components/views/rooms/RoomPreviewBar.tsx +++ b/src/components/views/rooms/RoomPreviewBar.tsx @@ -62,6 +62,7 @@ enum MessageCase { OtherError = "OtherError", PromptAskToJoin = "PromptAskToJoin", Knocked = "Knocked", + RequestDenied = "requestDenied", } interface IProps { @@ -188,7 +189,11 @@ export default class RoomPreviewBar extends React.Component { const myMember = this.getMyMember(); if (myMember) { + const previousMembership = myMember.events.member?.getPrevContent().membership; if (myMember.isKicked()) { + if (previousMembership === "knock") { + return MessageCase.RequestDenied; + } return MessageCase.Kicked; } else if (myMember.membership === "ban") { return MessageCase.Banned; @@ -397,6 +402,21 @@ export default class RoomPreviewBar extends React.Component { } break; } + case MessageCase.RequestDenied: { + title = _t("You have been denied access"); + + subTitle = _t( + "As you have been denied access, you cannot rejoin unless you are invited by the admin or moderator of the group.", + ); + + 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) { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 39e957832c8..5be75775b88 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2150,6 +2150,8 @@ "Forget this space": "Forget this space", "Forget this room": "Forget this room", "Re-join": "Re-join", + "You have been denied access": "You have been denied access", + "As you have been denied access, you cannot rejoin unless you are invited by the admin or moderator of the group.": "As you have been denied access, you cannot rejoin unless you are invited by the admin or moderator of the group.", "You were banned from %(roomName)s by %(memberName)s": "You were banned from %(roomName)s by %(memberName)s", "You were banned by %(memberName)s": "You were banned by %(memberName)s", "Something went wrong with your invite to %(roomName)s": "Something went wrong with your invite to %(roomName)s", diff --git a/test/components/views/rooms/RoomPreviewBar-test.tsx b/test/components/views/rooms/RoomPreviewBar-test.tsx index b2ed656924f..6f2805d164f 100644 --- a/test/components/views/rooms/RoomPreviewBar-test.tsx +++ b/test/components/views/rooms/RoomPreviewBar-test.tsx @@ -45,23 +45,27 @@ const makeMockRoomMember = ({ membership, content, memberContent, + oldMembership, }: { userId?: string; isKicked?: boolean; - membership?: "invite" | "ban"; + membership?: "invite" | "ban" | "leave"; content?: Partial; memberContent?: Partial; + oldMembership?: "join" | "knock"; }) => ({ userId, rawDisplayName: `${userId} name`, isKicked: jest.fn().mockReturnValue(!!isKicked), getContent: jest.fn().mockReturnValue(content || {}), + getPrevContent: jest.fn().mockReturnValue(content || {}), membership, events: { member: { getSender: jest.fn().mockReturnValue("@kicker:test.com"), getContent: jest.fn().mockReturnValue({ reason: "test reason", ...memberContent }), + getPrevContent: jest.fn().mockReturnValue({ membership: oldMembership, ...memberContent }), }, }, } as unknown as RoomMember); @@ -168,11 +172,33 @@ describe("", () => { it("renders kicked message", () => { const room = createRoom(roomId, otherUserId); jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ isKicked: true })); - const component = getComponent({ loading: true, room }); + const component = getComponent({ room, promptAskToJoin: true }); + + expect(getMessage(component)).toMatchSnapshot(); + }); + + it("renders denied request message", () => { + const room = createRoom(roomId, otherUserId); + jest.spyOn(room, "getMember").mockReturnValue( + makeMockRoomMember({ isKicked: true, membership: "leave", oldMembership: "knock" }), + ); + const component = getComponent({ room, promptAskToJoin: true }); expect(getMessage(component)).toMatchSnapshot(); }); + it("triggers the primary action callback for denied request", () => { + const onForgetClick = jest.fn(); + const room = createRoom(roomId, otherUserId); + jest.spyOn(room, "getMember").mockReturnValue( + makeMockRoomMember({ isKicked: true, membership: "leave", oldMembership: "knock" }), + ); + const component = getComponent({ room, promptAskToJoin: true, onForgetClick }); + + fireEvent.click(getPrimaryActionButton(component)!); + expect(onForgetClick).toHaveBeenCalled(); + }); + it("renders banned message", () => { const room = createRoom(roomId, otherUserId); jest.spyOn(room, "getMember").mockReturnValue(makeMockRoomMember({ membership: "ban" })); diff --git a/test/components/views/rooms/__snapshots__/RoomPreviewBar-test.tsx.snap b/test/components/views/rooms/__snapshots__/RoomPreviewBar-test.tsx.snap index d193fbea780..2bd4ebb47dc 100644 --- a/test/components/views/rooms/__snapshots__/RoomPreviewBar-test.tsx.snap +++ b/test/components/views/rooms/__snapshots__/RoomPreviewBar-test.tsx.snap @@ -107,6 +107,19 @@ exports[` renders banned message 1`] = ` `; +exports[` renders denied request message 1`] = ` +
+

+ You have been denied access +

+

+ As you have been denied access, you cannot rejoin unless you are invited by the admin or moderator of the group. +

+
+`; + exports[` renders kicked message 1`] = `