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

Disable redacting reactions if we don't have sufficient permissions #8767

Merged
merged 11 commits into from
Jun 10, 2022
4 changes: 4 additions & 0 deletions res/css/views/emojipicker/_EmojiPicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ limitations under the License.
list-style: none;
width: 38px;
cursor: pointer;

&.mx_AccessibleButton_disabled {
cursor: not-allowed;
}
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
}

.mx_EmojiPicker_item {
Expand Down
10 changes: 8 additions & 2 deletions src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export interface IRoomState {
searchInProgress?: boolean;
callState?: CallState;
canPeek: boolean;
canSelfRedact: boolean;
showApps: boolean;
isPeeking: boolean;
showRightPanel: boolean;
Expand Down Expand Up @@ -251,6 +252,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
searchResults: null,
callState: null,
canPeek: false,
canSelfRedact: false,
showApps: false,
isPeeking: false,
showRightPanel: false,
Expand Down Expand Up @@ -1165,10 +1167,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
private updatePermissions(room: Room) {
if (room) {
const me = this.context.getUserId();
const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me);
const canReact = (
room.getMyMembership() === "join" &&
room.currentState.maySendEvent(EventType.Reaction, me)
);
const canSendMessages = room.maySendMessage();
const canSelfRedact = room.currentState.maySendEvent(EventType.RoomRedaction, me);

this.setState({ canReact, canSendMessages });
this.setState({ canReact, canSendMessages, canSelfRedact });
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/components/views/emojipicker/Category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ interface IProps {
onClick(emoji: IEmoji): void;
onMouseEnter(emoji: IEmoji): void;
onMouseLeave(emoji: IEmoji): void;
isEmojiDisabled?: (unicode: string) => boolean;
}

class Category extends React.PureComponent<IProps> {
Expand All @@ -60,6 +61,7 @@ class Category extends React.PureComponent<IProps> {
onClick={onClick}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
disabled={this.props.isEmojiDisabled?.(emoji.unicode)}
/>
))
}</div>);
Expand Down
2 changes: 2 additions & 0 deletions src/components/views/emojipicker/Emoji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface IProps {
onClick(emoji: IEmoji): void;
onMouseEnter(emoji: IEmoji): void;
onMouseLeave(emoji: IEmoji): void;
disabled?: boolean;
}

class Emoji extends React.PureComponent<IProps> {
Expand All @@ -40,6 +41,7 @@ class Emoji extends React.PureComponent<IProps> {
onMouseLeave={() => onMouseLeave(emoji)}
className="mx_EmojiPicker_item_wrapper"
label={emoji.unicode}
disabled={this.props.disabled}
>
<div className={`mx_EmojiPicker_item ${isSelected ? 'mx_EmojiPicker_item_selected' : ''}`}>
{ emoji.unicode }
Expand Down
2 changes: 2 additions & 0 deletions src/components/views/emojipicker/EmojiPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface IProps {
selectedEmojis?: Set<string>;
showQuickReactions?: boolean;
onChoose(unicode: string): boolean;
isEmojiDisabled?: (unicode: string) => boolean;
}

interface IState {
Expand Down Expand Up @@ -261,6 +262,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
onClick={this.onClickEmoji}
onMouseEnter={this.onHoverEmoji}
onMouseLeave={this.onHoverEmojiEnd}
isEmojiDisabled={this.props.isEmojiDisabled}
selectedEmojis={this.props.selectedEmojis}
/>
);
Expand Down
13 changes: 12 additions & 1 deletion src/components/views/emojipicker/ReactionPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class ReactionPicker extends React.Component<IProps, IState> {
}
}

private getReactions() {
private getReactions(): Record<string, string> {
if (!this.props.reactions) {
return {};
}
Expand All @@ -95,6 +95,8 @@ class ReactionPicker extends React.Component<IProps, IState> {
this.props.onFinished();
const myReactions = this.getReactions();
if (myReactions.hasOwnProperty(reaction)) {
if (this.props.mxEvent.isRedacted() || !this.context.canSelfRedact) return;

MatrixClientPeg.get().redactEvent(this.props.mxEvent.getRoomId(), myReactions[reaction]);
dis.dispatch<FocusComposerPayload>({
action: Action.FocusAComposer,
Expand All @@ -119,9 +121,18 @@ class ReactionPicker extends React.Component<IProps, IState> {
}
};

private isEmojiDisabled = (unicode: string): boolean => {
if (!this.getReactions()[unicode]) return false;
if (this.props.mxEvent.isRedacted()) return false;
Copy link
Member

Choose a reason for hiding this comment

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

this seems backwards, surely this should be return true?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean the emoji button should be disabled if we don't have a reaction of its kind yet?

Copy link
Member

Choose a reason for hiding this comment

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

This looks to be saying, if the target event isRedacted then isEmojiDisabled=false, surely we shouldn't allow users to react to already redacted events

Copy link
Contributor Author

@SimonBrandner SimonBrandner Jun 10, 2022

Choose a reason for hiding this comment

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

Oh, you mean the other line :D Do we ever show the ReactionRow for deleted events?

Copy link
Member

Choose a reason for hiding this comment

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

If we don't then why is this line here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I was confused and actually meant to write something else 😅 - the line is now gone

if (this.context.canSelfRedact) return false;

return true;
};

render() {
return <EmojiPicker
onChoose={this.onChoose}
isEmojiDisabled={this.isEmojiDisabled}
selectedEmojis={this.state.selectedEmojis}
showQuickReactions={true}
data-testid='mx_ReactionPicker'
Expand Down
5 changes: 4 additions & 1 deletion src/components/views/messages/ReactionsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
mxEvent={mxEvent}
reactionEvents={events}
myReactionEvent={myReactionEvent}
disabled={!this.context.canReact}
disabled={
!this.context.canReact ||
(myReactionEvent && !myReactionEvent.isRedacted() && !this.context.canSelfRedact)
}
/>;
}).filter(item => !!item);

Expand Down
1 change: 1 addition & 0 deletions src/components/views/messages/ReactionsRowButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface IState {

export default class ReactionsRowButton extends React.PureComponent<IProps, IState> {
static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;

state = {
tooltipRendered: false,
Expand Down
1 change: 1 addition & 0 deletions src/contexts/RoomContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const RoomContext = createContext<IRoomState>({
showTopUnreadMessagesBar: false,
statusBarVisible: false,
canReact: false,
canSelfRedact: false,
canSendMessages: false,
resizing: false,
layout: Layout.Group,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ function createRoomState(room: Room, narrow: boolean): IRoomState {
shouldPeek: true,
membersLoaded: false,
numUnreadMessages: 0,
canSelfRedact: false,
canPeek: false,
showApps: false,
isPeeking: false,
Expand Down
8 changes: 4 additions & 4 deletions test/components/views/rooms/SendMessageComposer-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,18 @@ const WrapWithProviders: React.FC<{
</MatrixClientContext.Provider>;

describe('<SendMessageComposer/>', () => {
const defaultRoomContext = {
const defaultRoomContext: IRoomState = {
roomLoading: true,
peekLoading: false,
shouldPeek: true,
membersLoaded: false,
numUnreadMessages: 0,
searching: false,
guestsCanJoin: false,
canPeek: false,
showApps: false,
isPeeking: false,
showRightPanel: true,
joining: false,
atEndOfLiveTimeline: true,
atEndOfLiveTimelineInit: false,
showTopUnreadMessagesBar: false,
statusBarVisible: false,
canReact: false,
Expand All @@ -82,6 +79,9 @@ describe('<SendMessageComposer/>', () => {
matrixClientIsReady: false,
timelineRenderingType: TimelineRenderingType.Room,
liveTimeline: undefined,
canSelfRedact: false,
resizing: false,
narrow: false,
};
describe("createMessageContent", () => {
const permalinkCreator = jest.fn() as any;
Expand Down