Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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
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
18 changes: 15 additions & 3 deletions src/components/views/emojipicker/ReactionPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import dis from "../../../dispatcher/dispatcher";
import { Action } from '../../../dispatcher/actions';
import RoomContext from "../../../contexts/RoomContext";
import { FocusComposerPayload } from '../../../dispatcher/payloads/FocusComposerPayload';
import { canRedact } from "../messages/ReactionsRowButton";

interface IProps {
mxEvent: MatrixEvent;
Expand Down Expand Up @@ -73,15 +74,15 @@ class ReactionPicker extends React.Component<IProps, IState> {
}
}

private getReactions() {
private getReactions(): Record<string, MatrixEvent> {
if (!this.props.reactions) {
return {};
}
const userId = MatrixClientPeg.get().getUserId();
const myAnnotations = this.props.reactions.getAnnotationsBySender()[userId] || [];
return Object.fromEntries([...myAnnotations]
.filter(event => !event.isRedacted())
.map(event => [event.getRelation().key, event.getId()]));
.map(event => [event.getRelation().key, event]));
}

private onReactionsChange = () => {
Expand All @@ -93,9 +94,12 @@ class ReactionPicker extends React.Component<IProps, IState> {
private onChoose = (reaction: string) => {
this.componentWillUnmount();
this.props.onFinished();
const roomId = this.props.mxEvent.getRoomId();
const myReactions = this.getReactions();
if (myReactions.hasOwnProperty(reaction)) {
MatrixClientPeg.get().redactEvent(this.props.mxEvent.getRoomId(), myReactions[reaction]);
if (!canRedact(roomId, myReactions[reaction])) return;

MatrixClientPeg.get().redactEvent(roomId, myReactions[reaction].getId());
dis.dispatch<FocusComposerPayload>({
action: Action.FocusAComposer,
context: this.context.timelineRenderingType,
Expand All @@ -119,9 +123,17 @@ class ReactionPicker extends React.Component<IProps, IState> {
}
};

private isEmojiDisabled = (unicode: string): boolean => {
const reaction = this.getReactions()[unicode];

if (!reaction) return false;
return !canRedact(this.props.mxEvent.getRoomId(), reaction);
};

render() {
return <EmojiPicker
onChoose={this.onChoose}
isEmojiDisabled={this.isEmojiDisabled}
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
selectedEmojis={this.state.selectedEmojis}
showQuickReactions={true}
data-testid='mx_ReactionPicker'
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/ReactionsRowButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import AccessibleButton from "../elements/AccessibleButton";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { MatrixClientPeg } from "../../../MatrixClientPeg";

const canRedact = (roomId: string, mxEvent: MatrixEvent): boolean => {
export const canRedact = (roomId: string, mxEvent: MatrixEvent): boolean => {
SimonBrandner marked this conversation as resolved.
Show resolved Hide resolved
const client = MatrixClientPeg.get();
const room = client.getRoom(roomId);
return room.currentState.maySendRedactionForEvent(mxEvent, client.getUserId());
Expand Down