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'; import { ConversationModel } from './conversations';
type MessageModelType = 'incoming' | 'outgoing'; type MessageModelType = 'incoming' | 'outgoing';
@ -45,6 +46,74 @@ interface MessageAttributes {
status: MessageDeliveryStatus; 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> { export interface MessageModel extends Backbone.Model<MessageAttributes> {
idForLogging: () => string; idForLogging: () => string;
isGroupUpdate: () => boolean; isGroupUpdate: () => boolean;
@ -62,7 +131,7 @@ export interface MessageModel extends Backbone.Model<MessageAttributes> {
handleMessageSentSuccess: (sentMessage: any, wrappedEnvelope: any) => any; handleMessageSentSuccess: (sentMessage: any, wrappedEnvelope: any) => any;
handleMessageSentFailure: (sentMessage: any, error: any) => any; handleMessageSentFailure: (sentMessage: any, error: any) => any;
propsForMessage?: any; propsForMessage?: MessageRegularProps;
propsForTimerNotification?: any; propsForTimerNotification?: any;
propsForResetSessionNotification?: any; propsForResetSessionNotification?: any;
propsForGroupInvitation?: any; propsForGroupInvitation?: any;

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

@ -38,6 +38,7 @@ import uuid from 'uuid';
import { InView } from 'react-intersection-observer'; import { InView } from 'react-intersection-observer';
import { DefaultTheme, withTheme } from 'styled-components'; import { DefaultTheme, withTheme } from 'styled-components';
import { MessageMetadata } from './message/MessageMetadata'; import { MessageMetadata } from './message/MessageMetadata';
import { MessageRegularProps } from '../../../js/models/messages';
// Same as MIN_WIDTH in ImageGrid.tsx // Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200; const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -49,74 +50,6 @@ interface LinkPreviewType {
image?: AttachmentType; 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 { interface State {
expiring: boolean; expiring: boolean;
expired: boolean; expired: boolean;
@ -126,14 +59,14 @@ interface State {
const EXPIRATION_CHECK_MINIMUM = 2000; const EXPIRATION_CHECK_MINIMUM = 2000;
const EXPIRED_DELAY = 600; const EXPIRED_DELAY = 600;
class MessageInner extends React.PureComponent<Props, State> { class MessageInner extends React.PureComponent<MessageRegularProps, State> {
public handleImageErrorBound: () => void; public handleImageErrorBound: () => void;
public expirationCheckInterval: any; public expirationCheckInterval: any;
public expiredTimeout: any; public expiredTimeout: any;
public ctxMenuID: string; public ctxMenuID: string;
public constructor(props: Props) { public constructor(props: MessageRegularProps) {
super(props); super(props);
this.handleImageErrorBound = this.handleImageError.bind(this); this.handleImageErrorBound = this.handleImageError.bind(this);

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

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

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

Loading…
Cancel
Save