fix being able to remove messages from anyone as a moderator

pull/1438/head
Audric Ackermann 4 years ago
parent dc0733968d
commit 20c806be2d
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -1,3 +1,4 @@
import { LocalizerType } from '../../ts/types/Util';
import { ConversationModel } from './conversations';
type MessageModelType = 'incoming' | 'outgoing';
@ -45,6 +46,74 @@ interface MessageAttributes {
status: MessageDeliveryStatus;
}
export interface MessageRegularProps {
disableMenu?: boolean;
isDeletable: boolean;
isAdmin?: boolean;
weAreAdmin?: boolean;
text?: string;
bodyPending?: boolean;
id: string;
collapseMetadata?: boolean;
direction: 'incoming' | 'outgoing';
timestamp: number;
serverTimestamp?: number;
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error' | 'pow';
// What if changed this over to a single contact like quote, and put the events on it?
contact?: Contact & {
hasSignalAccount: boolean;
onSendMessage?: () => void;
onClick?: () => void;
};
authorName?: string;
authorProfileName?: string;
/** Note: this should be formatted for display */
authorPhoneNumber: string;
conversationType: 'group' | 'direct';
attachments?: Array<AttachmentType>;
quote?: {
text: string;
attachment?: QuotedAttachmentType;
isFromMe: boolean;
authorPhoneNumber: string;
authorProfileName?: string;
authorName?: string;
messageId?: string;
onClick: (data: any) => void;
referencedMessageNotFound: boolean;
};
previews: Array<LinkPreviewType>;
authorAvatarPath?: string;
isExpired: boolean;
expirationLength?: number;
expirationTimestamp?: number;
convoId: string;
isPublic?: boolean;
isRss?: boolean;
selected: boolean;
isKickedFromGroup: boolean;
// whether or not to show check boxes
multiSelectMode: boolean;
firstMessageOfSeries: boolean;
isUnread: boolean;
isQuotedMessageToAnimate?: boolean;
onClickAttachment?: (attachment: AttachmentType) => void;
onClickLinkPreview?: (url: string) => void;
onCopyText?: () => void;
onSelectMessage: (messageId: string) => void;
onReply?: (messagId: number) => void;
onRetrySend?: () => void;
onDownload?: (attachment: AttachmentType) => void;
onDeleteMessage: (messageId: string) => void;
onCopyPubKey?: () => void;
onBanUser?: () => void;
onShowDetail: () => void;
onShowUserDetails: (userPubKey: string) => void;
markRead: (readAt: number) => Promise<void>;
theme: DefaultTheme;
}
export interface MessageModel extends Backbone.Model<MessageAttributes> {
idForLogging: () => string;
isGroupUpdate: () => boolean;
@ -62,7 +131,7 @@ export interface MessageModel extends Backbone.Model<MessageAttributes> {
handleMessageSentSuccess: (sentMessage: any, wrappedEnvelope: any) => any;
handleMessageSentFailure: (sentMessage: any, error: any) => any;
propsForMessage?: any;
propsForMessage?: MessageRegularProps;
propsForTimerNotification?: any;
propsForResetSessionNotification?: any;
propsForGroupInvitation?: any;

@ -572,6 +572,7 @@
const convoId = conversation ? conversation.id : undefined;
const isGroup = !!conversation && !conversation.isPrivate();
const isPublic = !!this.get('isPublic');
const attachments = this.get('attachments') || [];
@ -599,15 +600,11 @@
isUnread: this.isUnread(),
expirationLength,
expirationTimestamp,
isPublic: !!this.get('isPublic'),
isPublic,
isRss: !!this.get('isRss'),
isKickedFromGroup:
conversation && conversation.get('isKickedFromGroup'),
isDeletable:
!this.get('isPublic') ||
isAdmin ||
phoneNumber === textsecure.storage.user.getNumber(),
isAdmin,
isAdmin, // if the sender is an admin (not us)
onCopyText: () => this.copyText(),
onCopyPubKey: () => this.copyPubKey(),

@ -38,6 +38,7 @@ import uuid from 'uuid';
import { InView } from 'react-intersection-observer';
import { DefaultTheme, withTheme } from 'styled-components';
import { MessageMetadata } from './message/MessageMetadata';
import { MessageRegularProps } from '../../../js/models/messages';
// Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -49,74 +50,6 @@ interface LinkPreviewType {
image?: AttachmentType;
}
export interface Props {
disableMenu?: boolean;
isDeletable: boolean;
isAdmin?: boolean;
weAreAdmin?: boolean;
text?: string;
bodyPending?: boolean;
id: string;
collapseMetadata?: boolean;
direction: 'incoming' | 'outgoing';
timestamp: number;
serverTimestamp?: number;
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error' | 'pow';
// What if changed this over to a single contact like quote, and put the events on it?
contact?: Contact & {
hasSignalAccount: boolean;
onSendMessage?: () => void;
onClick?: () => void;
};
authorName?: string;
authorProfileName?: string;
/** Note: this should be formatted for display */
authorPhoneNumber: string;
conversationType: 'group' | 'direct';
attachments?: Array<AttachmentType>;
quote?: {
text: string;
attachment?: QuotedAttachmentType;
isFromMe: boolean;
authorPhoneNumber: string;
authorProfileName?: string;
authorName?: string;
messageId?: string;
onClick: (data: any) => void;
referencedMessageNotFound: boolean;
};
previews: Array<LinkPreviewType>;
authorAvatarPath?: string;
isExpired: boolean;
expirationLength?: number;
expirationTimestamp?: number;
convoId: string;
isPublic?: boolean;
isRss?: boolean;
selected: boolean;
isKickedFromGroup: boolean;
// whether or not to show check boxes
multiSelectMode: boolean;
firstMessageOfSeries: boolean;
isUnread: boolean;
isQuotedMessageToAnimate?: boolean;
onClickAttachment?: (attachment: AttachmentType) => void;
onClickLinkPreview?: (url: string) => void;
onCopyText?: () => void;
onSelectMessage: (messageId: string) => void;
onReply?: (messagId: number) => void;
onRetrySend?: () => void;
onDownload?: (attachment: AttachmentType) => void;
onDeleteMessage: (messageId: string) => void;
onCopyPubKey?: () => void;
onBanUser?: () => void;
onShowDetail: () => void;
onShowUserDetails: (userPubKey: string) => void;
markRead: (readAt: number) => Promise<void>;
theme: DefaultTheme;
}
interface State {
expiring: boolean;
expired: boolean;
@ -126,14 +59,14 @@ interface State {
const EXPIRATION_CHECK_MINIMUM = 2000;
const EXPIRED_DELAY = 600;
class MessageInner extends React.PureComponent<Props, State> {
class MessageInner extends React.PureComponent<MessageRegularProps, State> {
public handleImageErrorBound: () => void;
public expirationCheckInterval: any;
public expiredTimeout: any;
public ctxMenuID: string;
public constructor(props: Props) {
public constructor(props: MessageRegularProps) {
super(props);
this.handleImageErrorBound = this.handleImageError.bind(this);

@ -4,7 +4,8 @@ import moment from 'moment';
import { Avatar } from '../Avatar';
import { ContactName } from './ContactName';
import { Message, Props as MessageProps } from './Message';
import { Message } from './Message';
import { MessageRegularProps } from '../../../js/models/messages';
interface Contact {
status: string;
@ -26,7 +27,7 @@ interface Props {
sentAt: number;
receivedAt: number;
message: MessageProps;
message: MessageRegularProps;
errors: Array<Error>;
contacts: Array<Contact>;

@ -294,8 +294,8 @@ export class SessionConversation extends React.Component<Props, State> {
const showMessageDetails = !!messageDetailShowProps;
const isPublic = selectedConversation.isPublic || false;
const isPrivate = selectedConversation.type === 'direct';
const isPrivate = selectedConversation.type === 'direct';
return (
<SessionTheme theme={this.props.theme}>
<div className="conversation-header">{this.renderHeader()}</div>

@ -12,7 +12,10 @@ import { AttachmentType } from '../../../types/Attachment';
import { GroupNotification } from '../../conversation/GroupNotification';
import { GroupInvitation } from '../../conversation/GroupInvitation';
import { ConversationType } from '../../../state/ducks/conversations';
import { MessageModel } from '../../../../js/models/messages';
import {
MessageModel,
MessageRegularProps,
} from '../../../../js/models/messages';
import { SessionLastSeenIndicator } from './SessionLastSeedIndicator';
import { VerificationNotification } from '../../conversation/VerificationNotification';
import { ToastUtils } from '../../../session/utils';
@ -296,12 +299,25 @@ export class SessionMessagesList extends React.Component<Props, State> {
</>
);
}
if (!messageProps) {
return;
}
if (messageProps.conversationType === 'group') {
messageProps.weAreAdmin = conversation.groupAdmins?.includes(
ourPrimary
);
}
// a message is deletable if
// either we sent it,
// or the convo is not a public one (in this case, we will only be able to delete for us)
// or the convo is public and we are an admin
const isDeletable =
messageProps.authorPhoneNumber === this.props.ourPrimary ||
!conversation.isPublic ||
(conversation.isPublic && !!messageProps.weAreAdmin);
messageProps.isDeletable = isDeletable;
// firstMessageOfSeries tells us to render the avatar only for the first message
// in a series of messages from the same user
@ -322,7 +338,7 @@ export class SessionMessagesList extends React.Component<Props, State> {
}
private renderMessage(
messageProps: any,
messageProps: MessageRegularProps,
firstMessageOfSeries: boolean,
multiSelectMode: boolean,
message: MessageModel
@ -331,7 +347,6 @@ export class SessionMessagesList extends React.Component<Props, State> {
!!messageProps?.id &&
this.props.selectedMessages.includes(messageProps.id);
messageProps.i18n = window.i18n;
messageProps.selected = selected;
messageProps.firstMessageOfSeries = firstMessageOfSeries;
@ -344,7 +359,7 @@ export class SessionMessagesList extends React.Component<Props, State> {
void this.props.showMessageDetails(messageDetailsProps);
};
messageProps.onClickAttachment = (attachment: any) => {
messageProps.onClickAttachment = (attachment: AttachmentType) => {
this.props.onClickAttachment(attachment, messageProps);
};
messageProps.onDownload = (attachment: AttachmentType) => {

Loading…
Cancel
Save