mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-07-10 07:14:05 +01:00
Always allow reporting chats as spam
This commit is contained in:
@@ -6508,6 +6508,10 @@
|
||||
"messageformat": "Unblock group",
|
||||
"description": "This is a button to unblock a group"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam": {
|
||||
"messageformat": "Report spam",
|
||||
"description": "This is a button to report spam"
|
||||
},
|
||||
"icu:ConversationDetailsActions--archive": {
|
||||
"messageformat": "Archive chat",
|
||||
"description": "This is a button to archive a chat"
|
||||
@@ -6576,6 +6580,26 @@
|
||||
"messageformat": "Unblock",
|
||||
"description": "This is the modal button to confirm unblock of a group"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam-modal-title": {
|
||||
"messageformat": "Report spam?",
|
||||
"description": "This is the modal title for confirming reporting spam"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam-modal-content-direct": {
|
||||
"messageformat": "Signal will be notified that this person may be sending spam. Signal can’t see the content of any chats.",
|
||||
"description": "This is the modal content for confirming reporting a 1-1 chat as spam"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam-modal-content-group": {
|
||||
"messageformat": "Signal will be notified that the person who invited you to this group may be sending spam. Signal can't see the content of any chats.",
|
||||
"description": "This is the modal content for confirming reporting a group as spam"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam-modal-report-spam": {
|
||||
"messageformat": "Report spam",
|
||||
"description": "This is the modal button to confirm reporting spam"
|
||||
},
|
||||
"icu:ConversationDetailsActions--report-spam-modal-report-and-block": {
|
||||
"messageformat": "Report and block",
|
||||
"description": "This is the modal button to confirm reporting spam and block"
|
||||
},
|
||||
"icu:ConversationDetailsHeader--members": {
|
||||
"messageformat": "{number, plural, one {# member} other {# members}}",
|
||||
"description": "This is the number of members in a group"
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
}
|
||||
|
||||
&__block-group,
|
||||
&__report-spam,
|
||||
&__terminate-group,
|
||||
&__delete {
|
||||
color: variables.$color-accent-red;
|
||||
@@ -358,6 +359,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
&--spam {
|
||||
&::after {
|
||||
@include details-icon(
|
||||
'../images/icons/v3/spam/spam.svg',
|
||||
variables.$color-accent-red,
|
||||
variables.$color-accent-red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
&--terminate {
|
||||
&::after {
|
||||
@include details-icon(
|
||||
|
||||
@@ -127,6 +127,7 @@ const createProps = (
|
||||
setMuteExpiration: action('setMuteExpiration'),
|
||||
showToast: action('showToast'),
|
||||
userAvatarData: [],
|
||||
reportSpam: action('reportSpam'),
|
||||
terminateGroup: action('terminateGroup'),
|
||||
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
||||
toggleAboutContactModal: action('toggleAboutContactModal'),
|
||||
|
||||
@@ -143,6 +143,7 @@ type ActionProps = {
|
||||
onOutgoingVideoCallInConversation: (conversationId: string) => unknown;
|
||||
pushPanelForConversation: PushPanelForConversationActionType;
|
||||
replaceAvatar: ReplaceAvatarActionType;
|
||||
reportSpam: (id: string) => void;
|
||||
saveAvatarToDisk: SaveAvatarToDiskActionType;
|
||||
searchInConversation: (id: string) => unknown;
|
||||
setDisappearingMessages: (id: string, seconds: DurationInSeconds) => void;
|
||||
@@ -215,6 +216,7 @@ export function ConversationDetails({
|
||||
renderChooseGroupMembersModal,
|
||||
renderConfirmAdditionsModal,
|
||||
replaceAvatar,
|
||||
reportSpam,
|
||||
saveAvatarToDisk,
|
||||
searchInConversation,
|
||||
selectedNavTab,
|
||||
@@ -882,11 +884,17 @@ export function ConversationDetails({
|
||||
isBlocked={Boolean(conversation.isBlocked)}
|
||||
isGroup={isGroup}
|
||||
isGroupTerminated={isGroupTerminated}
|
||||
isSignalConversation={isSignalConversation}
|
||||
left={Boolean(conversation.left)}
|
||||
onArchive={onConversationArchive}
|
||||
onDelete={onConversationDeleteMessages}
|
||||
onUnarchive={onConversationUnarchive}
|
||||
onLeave={() => leaveGroup(conversation.id)}
|
||||
onReportSpam={() => reportSpam(conversation.id)}
|
||||
onReportSpamAndBlock={() => {
|
||||
reportSpam(conversation.id);
|
||||
blockConversation(conversation.id);
|
||||
}}
|
||||
onTerminateGroup={() => terminateGroup(conversation.id)}
|
||||
/>
|
||||
)}
|
||||
|
||||
+3
@@ -39,10 +39,13 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||
isGroupTerminated: isBoolean(overrideProps.isGroupTerminated)
|
||||
? overrideProps.isGroupTerminated
|
||||
: false,
|
||||
isSignalConversation: false,
|
||||
left: isBoolean(overrideProps.left) ? overrideProps.left : false,
|
||||
onArchive: action('onArchive'),
|
||||
onDelete: action('onDelet'),
|
||||
onLeave: action('onLeave'),
|
||||
onReportSpamAndBlock: action('onBlockAndReportSpam'),
|
||||
onReportSpam: action('onReportSpam'),
|
||||
onTerminateGroup: action('onTerminateGroup'),
|
||||
onUnarchive: action('onUnarchive'),
|
||||
});
|
||||
|
||||
@@ -29,11 +29,14 @@ export type Props = {
|
||||
isBlocked: boolean;
|
||||
isGroup: boolean;
|
||||
isGroupTerminated: boolean;
|
||||
isSignalConversation: boolean;
|
||||
left: boolean;
|
||||
onArchive: () => void;
|
||||
onDelete: () => void;
|
||||
onUnarchive: () => void;
|
||||
onLeave: () => void;
|
||||
onReportSpam: () => void;
|
||||
onReportSpamAndBlock: () => void;
|
||||
onTerminateGroup: () => void;
|
||||
};
|
||||
|
||||
@@ -49,11 +52,14 @@ export function ConversationDetailsActions({
|
||||
isBlocked,
|
||||
isGroup,
|
||||
isGroupTerminated,
|
||||
isSignalConversation,
|
||||
left,
|
||||
onArchive,
|
||||
onDelete,
|
||||
onUnarchive,
|
||||
onLeave,
|
||||
onReportSpamAndBlock,
|
||||
onReportSpam,
|
||||
onTerminateGroup,
|
||||
}: Props): React.JSX.Element {
|
||||
const [confirmLeave, gLeave] = useState<boolean>(false);
|
||||
@@ -61,6 +67,7 @@ export function ConversationDetailsActions({
|
||||
const [confirmGroupUnblock, gGroupUnblock] = useState<boolean>(false);
|
||||
const [confirmDirectBlock, gDirectBlock] = useState<boolean>(false);
|
||||
const [confirmDirectUnblock, gDirectUnblock] = useState<boolean>(false);
|
||||
const [confirmReportSpam, gConfirmReportSpam] = useState<boolean>(false);
|
||||
const [promptTerminateGroup, gPromptTerminateGroup] =
|
||||
useState<boolean>(false);
|
||||
const [confirmTerminateGroup, gConfirmTerminateGroup] =
|
||||
@@ -184,6 +191,26 @@ export function ConversationDetailsActions({
|
||||
);
|
||||
}
|
||||
|
||||
let reportSpamNode: ReactNode;
|
||||
if (!isSignalConversation) {
|
||||
reportSpamNode = (
|
||||
<PanelRow
|
||||
onClick={() => gConfirmReportSpam(true)}
|
||||
icon={
|
||||
<ConversationDetailsIcon
|
||||
ariaLabel={i18n('icu:ConversationDetailsActions--report-spam')}
|
||||
icon={IconType.spam}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<div className="ConversationDetails__report-spam">
|
||||
{i18n('icu:ConversationDetailsActions--report-spam')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let terminateGroupNode: ReactNode;
|
||||
if (canTerminateGroup) {
|
||||
terminateGroupNode = (
|
||||
@@ -267,6 +294,7 @@ export function ConversationDetailsActions({
|
||||
{blockNode}
|
||||
{archiveNode}
|
||||
{deleteNode}
|
||||
{reportSpamNode}
|
||||
</PanelSection>
|
||||
{terminateGroupNode && <PanelSection>{terminateGroupNode}</PanelSection>}
|
||||
{confirmLeave && (
|
||||
@@ -379,6 +407,43 @@ export function ConversationDetailsActions({
|
||||
</ConfirmationDialog>
|
||||
)}
|
||||
|
||||
{confirmReportSpam && (
|
||||
<ConfirmationDialog
|
||||
dialogName="ConversationDetailsAction.confirmSpam"
|
||||
actions={[
|
||||
{
|
||||
text: i18n(
|
||||
'icu:ConversationDetailsActions--report-spam-modal-report-spam'
|
||||
),
|
||||
action: onReportSpam,
|
||||
style: 'negative',
|
||||
},
|
||||
...(isBlocked
|
||||
? []
|
||||
: ([
|
||||
{
|
||||
text: i18n(
|
||||
'icu:ConversationDetailsActions--report-spam-modal-report-and-block'
|
||||
),
|
||||
action: onReportSpamAndBlock,
|
||||
style: 'negative',
|
||||
},
|
||||
] as const)),
|
||||
]}
|
||||
i18n={i18n}
|
||||
onClose={() => gConfirmReportSpam(false)}
|
||||
title={i18n('icu:MessageRequests--ReportAndMaybeBlockModal-title')}
|
||||
>
|
||||
{isGroup
|
||||
? i18n(
|
||||
'icu:ConversationDetailsActions--report-spam-modal-content-group'
|
||||
)
|
||||
: i18n(
|
||||
'icu:ConversationDetailsActions--report-spam-modal-content-direct'
|
||||
)}
|
||||
</ConfirmationDialog>
|
||||
)}
|
||||
|
||||
{promptTerminateGroup && (
|
||||
<ConfirmationDialog
|
||||
dialogName="ConversationDetailsAction.promptTerminateGroup"
|
||||
|
||||
@@ -32,6 +32,7 @@ export enum IconType {
|
||||
'official' = 'official',
|
||||
'reset' = 'reset',
|
||||
'share' = 'share',
|
||||
'spam' = 'spam',
|
||||
'spinner' = 'spinner',
|
||||
'tag' = 'tag',
|
||||
'terminate' = 'terminate',
|
||||
|
||||
@@ -3042,6 +3042,7 @@ type MaybeUpdatePropsType = Readonly<{
|
||||
newRevision?: number;
|
||||
receivedAt?: number;
|
||||
sentAt?: number;
|
||||
serverGuid?: string;
|
||||
dropInitialJoinMessage?: boolean;
|
||||
force?: boolean;
|
||||
groupChange?: WrappedGroupChangeType;
|
||||
@@ -3102,6 +3103,7 @@ export async function maybeUpdateGroup(
|
||||
newRevision,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
serverGuid,
|
||||
}: MaybeUpdatePropsType,
|
||||
{ viaFirstStorageSync = false } = {}
|
||||
): Promise<void> {
|
||||
@@ -3120,7 +3122,7 @@ export async function maybeUpdateGroup(
|
||||
});
|
||||
|
||||
await updateGroup(
|
||||
{ conversation, receivedAt, sentAt, updates },
|
||||
{ conversation, receivedAt, sentAt, serverGuid, updates },
|
||||
{ viaFirstStorageSync }
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -3147,11 +3149,13 @@ async function updateGroup(
|
||||
conversation,
|
||||
receivedAt,
|
||||
sentAt,
|
||||
serverGuid,
|
||||
updates,
|
||||
}: {
|
||||
conversation: ConversationModel;
|
||||
receivedAt?: number;
|
||||
sentAt?: number;
|
||||
serverGuid?: string;
|
||||
updates: UpdatesResultType;
|
||||
},
|
||||
{ viaFirstStorageSync = false } = {}
|
||||
@@ -3211,6 +3215,7 @@ async function updateGroup(
|
||||
conversationId: conversation.id,
|
||||
received_at_ms: syntheticSentAt,
|
||||
sent_at: syntheticSentAt,
|
||||
serverGuid,
|
||||
timestamp,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -10,25 +10,32 @@ import type { ConversationType } from '../../state/ducks/conversations.preload.t
|
||||
|
||||
const log = createLogger('addReportSpamJob');
|
||||
|
||||
// The Aci being reported is always the directConversation's Aci.
|
||||
// When groupConversationId is missing, then we report messages in the directConversation.
|
||||
// When groupConversationId is specified, then we report messages or group updates
|
||||
// from the Aci within that group.
|
||||
export async function addReportSpamJob({
|
||||
conversation,
|
||||
directConversation,
|
||||
getMessageServerGuidsForSpam,
|
||||
groupConversationId,
|
||||
jobQueue,
|
||||
}: Readonly<{
|
||||
conversation: Readonly<
|
||||
directConversation: Readonly<
|
||||
Pick<ConversationType, 'id' | 'type' | 'serviceId' | 'reportingToken'>
|
||||
>;
|
||||
getMessageServerGuidsForSpam: (
|
||||
conversationId: string
|
||||
conversationId: string,
|
||||
sourceServiceId?: string
|
||||
) => Promise<Array<string>>;
|
||||
groupConversationId?: string;
|
||||
jobQueue: Pick<typeof reportSpamJobQueue, 'add'>;
|
||||
}>): Promise<void> {
|
||||
assertDev(
|
||||
isDirectConversation(conversation),
|
||||
isDirectConversation(directConversation),
|
||||
'addReportSpamJob: cannot report spam for non-direct conversations'
|
||||
);
|
||||
|
||||
const { serviceId: aci } = conversation;
|
||||
const { serviceId: aci, reportingToken: token } = directConversation;
|
||||
if (!aci || !isAciString(aci)) {
|
||||
log.info(
|
||||
'got a conversation with no aci, which the server does not support. Doing nothing'
|
||||
@@ -36,7 +43,13 @@ export async function addReportSpamJob({
|
||||
return;
|
||||
}
|
||||
|
||||
const serverGuids = await getMessageServerGuidsForSpam(conversation.id);
|
||||
let serverGuids: Array<string> = [];
|
||||
if (groupConversationId) {
|
||||
serverGuids = await getMessageServerGuidsForSpam(groupConversationId, aci);
|
||||
} else {
|
||||
serverGuids = await getMessageServerGuidsForSpam(directConversation.id);
|
||||
}
|
||||
|
||||
if (!serverGuids.length) {
|
||||
// This can happen under normal conditions. We haven't always stored server GUIDs, so
|
||||
// a user might try to report spam for a conversation that doesn't have them. (It
|
||||
@@ -45,5 +58,5 @@ export async function addReportSpamJob({
|
||||
return;
|
||||
}
|
||||
|
||||
await jobQueue.add({ aci, serverGuids, token: conversation.reportingToken });
|
||||
await jobQueue.add({ aci, serverGuids, token });
|
||||
}
|
||||
|
||||
@@ -284,6 +284,7 @@ export async function handleDataMessage(
|
||||
newRevision: revision,
|
||||
receivedAt: message.get('received_at'),
|
||||
sentAt: message.get('sent_at'),
|
||||
serverGuid: message.get('serverGuid'),
|
||||
});
|
||||
} catch (error) {
|
||||
const errorText = Errors.toLogFormat(error);
|
||||
|
||||
@@ -1086,7 +1086,10 @@ type ReadableInterface = {
|
||||
limit: number,
|
||||
options: { maxVersion: number }
|
||||
) => Array<MessageType>;
|
||||
getMessageServerGuidsForSpam: (conversationId: string) => Array<string>;
|
||||
getMessageServerGuidsForSpam: (
|
||||
conversationId: string,
|
||||
sourceServiceId?: string
|
||||
) => Array<string>;
|
||||
|
||||
getJobsInQueue(queueType: string): Array<StoredJob>;
|
||||
|
||||
|
||||
+36
-12
@@ -8728,26 +8728,50 @@ export function incrementMessagesMigrationAttempts(
|
||||
|
||||
function getMessageServerGuidsForSpam(
|
||||
db: ReadableDB,
|
||||
conversationId: string
|
||||
conversationId: string,
|
||||
sourceServiceId?: string
|
||||
): Array<string> {
|
||||
// The server's maximum is 3, which is why you see `LIMIT 3` in this query. Note that we
|
||||
// use `pluck` here to only get the first column!
|
||||
// The server's maximum is 3.
|
||||
const limit = 3;
|
||||
|
||||
// Group reports -- sourceServiceId should be Aci matching addedBy of user who
|
||||
// added you to a group
|
||||
if (sourceServiceId != null) {
|
||||
return db
|
||||
.prepare(
|
||||
`
|
||||
SELECT DISTINCT serverGuid
|
||||
FROM messages
|
||||
WHERE conversationId = $conversationId
|
||||
AND sourceServiceId = $sourceServiceId
|
||||
AND type IS NOT 'outgoing'
|
||||
AND serverGuid IS NOT NULL
|
||||
ORDER BY received_at DESC, sent_at DESC
|
||||
LIMIT $limit;
|
||||
`,
|
||||
{
|
||||
pluck: true,
|
||||
}
|
||||
)
|
||||
.all({ conversationId, sourceServiceId, limit });
|
||||
}
|
||||
|
||||
return db
|
||||
.prepare(
|
||||
`
|
||||
SELECT serverGuid
|
||||
FROM messages
|
||||
WHERE conversationId = $conversationId
|
||||
AND type = 'incoming'
|
||||
AND serverGuid IS NOT NULL
|
||||
ORDER BY received_at DESC, sent_at DESC
|
||||
LIMIT 3;
|
||||
`,
|
||||
SELECT DISTINCT serverGuid
|
||||
FROM messages
|
||||
WHERE conversationId = $conversationId
|
||||
AND type IS NOT 'outgoing'
|
||||
AND serverGuid IS NOT NULL
|
||||
ORDER BY received_at DESC, sent_at DESC
|
||||
LIMIT $limit;
|
||||
`,
|
||||
{
|
||||
pluck: true,
|
||||
}
|
||||
)
|
||||
.all({ conversationId });
|
||||
.all({ conversationId, limit });
|
||||
}
|
||||
|
||||
function getExternalFilesForConversation(
|
||||
|
||||
@@ -196,7 +196,7 @@ import {
|
||||
SettingsPage,
|
||||
} from '../../types/Nav.std.ts';
|
||||
import { sortByMessageOrder } from '../../types/ForwardDraft.std.ts';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import {
|
||||
getConversationIdForLogging,
|
||||
getMessageIdForLogging,
|
||||
@@ -3783,17 +3783,27 @@ async function syncMessageRequestResponse(
|
||||
}
|
||||
}
|
||||
|
||||
function getConversationForReportSpam(
|
||||
function getDirectConversationForReportSpam(
|
||||
conversation: ConversationType
|
||||
): ConversationType | null {
|
||||
const ourAci = itemStorage.user.getAci();
|
||||
|
||||
if (conversation.type === 'group') {
|
||||
const addedBy = getAddedByForOurPendingInvitation(conversation);
|
||||
const addedBy = getAddedByForGroup(conversation);
|
||||
if (addedBy == null) {
|
||||
log.error(
|
||||
`getConversationForReportSpam: No addedBy found for ${conversation.id}`
|
||||
`getDirectConversationForReportSpam: No addedBy found for ${conversation.id}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (addedBy.serviceId === ourAci) {
|
||||
log.warn(
|
||||
"getDirectConversationForReportSpam: We added ourself to this group, but can't report ourself for spam."
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return addedBy;
|
||||
}
|
||||
|
||||
@@ -3813,19 +3823,23 @@ function reportSpam(
|
||||
return;
|
||||
}
|
||||
|
||||
const conversation = getConversationForReportSpam(conversationOrGroup);
|
||||
const conversationForSpam =
|
||||
getDirectConversationForReportSpam(conversationOrGroup);
|
||||
const conversationModel = window.ConversationController.get(
|
||||
conversation?.id
|
||||
conversationOrGroup?.id
|
||||
);
|
||||
if (!conversation || !conversationModel) {
|
||||
if (!conversationForSpam || !conversationModel) {
|
||||
log.error(
|
||||
`reportSpam: Conversation for report spam not found ${conversation?.id}. Doing nothing.`
|
||||
`reportSpam: Conversation for report spam not found ${conversationForSpam?.id}. Doing nothing.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||
const idForLogging = getConversationIdForLogging(conversation);
|
||||
const idForLogging = getConversationIdForLogging(conversationForSpam);
|
||||
const groupConversationId = isGroup(conversationOrGroup)
|
||||
? conversationOrGroup.id
|
||||
: undefined;
|
||||
|
||||
drop(
|
||||
longRunningTaskWrapper({
|
||||
@@ -3838,9 +3852,10 @@ function reportSpam(
|
||||
messageRequestEnum.SPAM
|
||||
),
|
||||
addReportSpamJob({
|
||||
conversation,
|
||||
directConversation: conversationForSpam,
|
||||
getMessageServerGuidsForSpam:
|
||||
DataReader.getMessageServerGuidsForSpam,
|
||||
groupConversationId,
|
||||
jobQueue: reportSpamJobQueue,
|
||||
}),
|
||||
]);
|
||||
@@ -3871,7 +3886,7 @@ function blockAndReportSpam(
|
||||
}
|
||||
|
||||
const conversationForSpam =
|
||||
getConversationForReportSpam(conversationOrGroup);
|
||||
getDirectConversationForReportSpam(conversationOrGroup);
|
||||
const conversationModel = window.ConversationController.get(
|
||||
conversationForSpam?.id
|
||||
);
|
||||
@@ -3881,8 +3896,12 @@ function blockAndReportSpam(
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const messageRequestEnum = Proto.SyncMessage.MessageRequestResponse.Type;
|
||||
const idForLogging = getConversationIdForLogging(conversationOrGroup);
|
||||
const groupConversationId = isGroup(conversationOrGroup)
|
||||
? conversationOrGroup.id
|
||||
: undefined;
|
||||
|
||||
if (conversationModel.getAci()) {
|
||||
drop(
|
||||
@@ -3895,13 +3914,13 @@ function blockAndReportSpam(
|
||||
conversationModel,
|
||||
messageRequestEnum.BLOCK_AND_SPAM
|
||||
),
|
||||
conversationForSpam != null &&
|
||||
addReportSpamJob({
|
||||
conversation: conversationForSpam,
|
||||
getMessageServerGuidsForSpam:
|
||||
DataReader.getMessageServerGuidsForSpam,
|
||||
jobQueue: reportSpamJobQueue,
|
||||
}),
|
||||
addReportSpamJob({
|
||||
directConversation: conversationForSpam,
|
||||
getMessageServerGuidsForSpam:
|
||||
DataReader.getMessageServerGuidsForSpam,
|
||||
groupConversationId,
|
||||
jobQueue: reportSpamJobQueue,
|
||||
}),
|
||||
]);
|
||||
|
||||
dispatch({
|
||||
|
||||
@@ -17,7 +17,7 @@ import type { ConversationType } from '../ducks/conversations.preload.ts';
|
||||
import { useConversationsActions } from '../ducks/conversations.preload.ts';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals.preload.ts';
|
||||
import { strictAssert } from '../../util/assert.std.ts';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import { getItems } from '../selectors/items.dom.ts';
|
||||
import { isFeaturedEnabledSelector } from '../../util/isFeatureEnabled.dom.ts';
|
||||
import { getCanAddLabel } from '../../types/GroupMemberLabels.std.ts';
|
||||
@@ -38,7 +38,7 @@ function isFromOrAddedByTrustedContact(
|
||||
return Boolean(conversation.name) || Boolean(conversation.profileSharing);
|
||||
}
|
||||
|
||||
const addedByConv = getAddedByForOurPendingInvitation(conversation);
|
||||
const addedByConv = getAddedByForGroup(conversation);
|
||||
if (!addedByConv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
} from '../../types/BodyRange.std.ts';
|
||||
import { hydrateRanges } from '../../util/BodyRange.node.ts';
|
||||
import { strictAssert } from '../../util/assert.std.ts';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import { AutoSubstituteAsciiEmojis } from '../../quill/auto-substitute-ascii-emojis/index.dom.tsx';
|
||||
import { imageToBlurHash } from '../../util/imageToBlurHash.dom.ts';
|
||||
import { isConversationSMSOnly } from '../../util/isConversationSMSOnly.std.ts';
|
||||
@@ -151,7 +151,7 @@ export const SmartCompositionArea = memo(function SmartCompositionArea({
|
||||
|
||||
const addedBy = useMemo(() => {
|
||||
if (conversation.type === 'group') {
|
||||
return getAddedByForOurPendingInvitation(conversation);
|
||||
return getAddedByForGroup(conversation);
|
||||
}
|
||||
return null;
|
||||
}, [conversation]);
|
||||
|
||||
@@ -133,6 +133,7 @@ export const SmartConversationDetails = memo(function SmartConversationDetails({
|
||||
onArchive,
|
||||
onMoveToInbox,
|
||||
replaceAvatar,
|
||||
reportSpam,
|
||||
saveAvatarToDisk,
|
||||
setDisappearingMessages,
|
||||
setMuteExpiration,
|
||||
@@ -295,6 +296,7 @@ export const SmartConversationDetails = memo(function SmartConversationDetails({
|
||||
renderChooseGroupMembersModal={renderChooseGroupMembersModal}
|
||||
renderConfirmAdditionsModal={renderConfirmAdditionsModal}
|
||||
replaceAvatar={replaceAvatar}
|
||||
reportSpam={reportSpam}
|
||||
saveAvatarToDisk={saveAvatarToDisk}
|
||||
searchInConversation={searchInConversation}
|
||||
selectedNavTab={selectedNavTab}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { CallMode } from '../../types/CallDisposition.std.ts';
|
||||
import { PanelType } from '../../types/Panels.std.ts';
|
||||
import { StoryViewModeType } from '../../types/Stories.std.ts';
|
||||
import { strictAssert } from '../../util/assert.std.ts';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import { getGroupMemberships } from '../../util/getGroupMemberships.dom.ts';
|
||||
import { isConversationSMSOnly } from '../../util/isConversationSMSOnly.std.ts';
|
||||
import { isGroupOrAdhocCallState } from '../../util/isGroupOrAdhocCall.std.ts';
|
||||
@@ -175,7 +175,7 @@ export const SmartConversationHeader = memo(function SmartConversationHeader({
|
||||
|
||||
const addedBy = useMemo(() => {
|
||||
if (conversation.type === 'group') {
|
||||
return getAddedByForOurPendingInvitation(conversation);
|
||||
return getAddedByForGroup(conversation);
|
||||
}
|
||||
return null;
|
||||
}, [conversation]);
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
} from '../ducks/conversations.preload.ts';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals.preload.ts';
|
||||
import { useStoriesActions } from '../ducks/stories.preload.ts';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import { getGroupMemberships } from '../../util/getGroupMemberships.dom.ts';
|
||||
import { useNavActions } from '../ducks/nav.std.ts';
|
||||
|
||||
@@ -35,7 +35,7 @@ function isFromOrAddedByTrustedContact(
|
||||
return Boolean(conversation.name) || Boolean(conversation.profileSharing);
|
||||
}
|
||||
|
||||
const addedByConv = getAddedByForOurPendingInvitation(conversation);
|
||||
const addedByConv = getAddedByForGroup(conversation);
|
||||
if (!addedByConv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
MessageRequestState,
|
||||
} from '../../components/conversation/MessageRequestActionsConfirmation.dom.tsx';
|
||||
import { useContactNameData } from '../../components/conversation/ContactName.dom.tsx';
|
||||
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation.preload.ts';
|
||||
import { getAddedByForGroup } from '../../util/getAddedByForGroup.preload.ts';
|
||||
import { strictAssert } from '../../util/assert.std.ts';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals.preload.ts';
|
||||
|
||||
@@ -31,7 +31,7 @@ export const SmartMessageRequestActionsConfirmation = memo(
|
||||
const conversation = getConversation(conversationId);
|
||||
const addedBy = useMemo(() => {
|
||||
if (conversation.type === 'group') {
|
||||
return getAddedByForOurPendingInvitation(conversation);
|
||||
return getAddedByForGroup(conversation);
|
||||
}
|
||||
return null;
|
||||
}, [conversation]);
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('addReportSpamJob', () => {
|
||||
|
||||
it('does nothing if the conversation lacks a serviceId', async () => {
|
||||
await addReportSpamJob({
|
||||
conversation: {
|
||||
directConversation: {
|
||||
...conversation,
|
||||
serviceId: undefined,
|
||||
},
|
||||
@@ -48,7 +48,7 @@ describe('addReportSpamJob', () => {
|
||||
getMessageServerGuidsForSpam.resolves([]);
|
||||
|
||||
await addReportSpamJob({
|
||||
conversation,
|
||||
directConversation: conversation,
|
||||
getMessageServerGuidsForSpam,
|
||||
jobQueue,
|
||||
});
|
||||
@@ -58,7 +58,7 @@ describe('addReportSpamJob', () => {
|
||||
|
||||
it('enqueues a job without a token', async () => {
|
||||
await addReportSpamJob({
|
||||
conversation,
|
||||
directConversation: conversation,
|
||||
getMessageServerGuidsForSpam,
|
||||
jobQueue,
|
||||
});
|
||||
@@ -76,7 +76,7 @@ describe('addReportSpamJob', () => {
|
||||
|
||||
it('enqueues a job with a token', async () => {
|
||||
await addReportSpamJob({
|
||||
conversation: {
|
||||
directConversation: {
|
||||
...conversation,
|
||||
reportingToken: 'uvw',
|
||||
},
|
||||
@@ -94,4 +94,23 @@ describe('addReportSpamJob', () => {
|
||||
token: 'uvw',
|
||||
});
|
||||
});
|
||||
|
||||
it('calls getMessageServerGuidsForSpam with groupConversationId', async () => {
|
||||
await addReportSpamJob({
|
||||
directConversation: {
|
||||
...conversation,
|
||||
reportingToken: 'uvw',
|
||||
},
|
||||
getMessageServerGuidsForSpam,
|
||||
groupConversationId: 'group',
|
||||
jobQueue,
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(getMessageServerGuidsForSpam);
|
||||
sinon.assert.calledWith(
|
||||
getMessageServerGuidsForSpam,
|
||||
'group',
|
||||
conversation.serviceId
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+12
-5
@@ -3,16 +3,23 @@
|
||||
import type { ConversationType } from '../state/ducks/conversations.preload.ts';
|
||||
import { itemStorage } from '../textsecure/Storage.preload.ts';
|
||||
|
||||
export function getAddedByForOurPendingInvitation(
|
||||
export function getAddedByForGroup(
|
||||
conversation: ConversationType
|
||||
): ConversationType | null {
|
||||
const ourAci = itemStorage.user.getCheckedAci();
|
||||
const ourPni = itemStorage.user.getPni();
|
||||
const addedBy = conversation.pendingMemberships?.find(
|
||||
|
||||
let addedByAci;
|
||||
addedByAci = conversation.pendingMemberships?.find(
|
||||
item => item.serviceId === ourAci || item.serviceId === ourPni
|
||||
)?.addedByUserId;
|
||||
if (addedBy == null) {
|
||||
return null;
|
||||
|
||||
if (addedByAci == null) {
|
||||
const conversationModel = window.ConversationController.get(
|
||||
conversation.id
|
||||
);
|
||||
addedByAci = conversationModel?.attributes.addedBy;
|
||||
}
|
||||
return window.ConversationController.get(addedBy)?.format() ?? null;
|
||||
|
||||
return window.ConversationController.get(addedByAci)?.format() ?? null;
|
||||
}
|
||||
Reference in New Issue
Block a user