diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 50142152458..65f5ce5a9ba 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -1235,9 +1235,13 @@
"messageformat": "{obsoleteConversationTitle} and {conversationTitle} are the same account. Your message history for both chats are here.",
"description": "Shown when we've discovered that two local conversations are the same remote account in an unusual way"
},
- "icu:ConversationMerge--notification--no-e164": {
+ "icu:ConversationMerge--notification--with-e164": {
+ "messageformat": "Your message history with {conversationTitle} and their number {obsoleteConversationNumber} has been merged.",
+ "description": "Shown when we've discovered that two local conversations are the same remote account in an unusual way, but we have the phone number for the old conversation"
+ },
+ "icu:ConversationMerge--notification--no-title": {
"messageformat": "Your message history with {conversationTitle} and another chat that belonged to them has been merged.",
- "description": "Shown when we've discovered that two local conversations are the same remote account in an unusual way, but we don't have the phone number for the old conversation"
+ "description": "Shown when we've discovered that two local conversations are the same remote account in an unusual way, but we don't have the title for the old conversation"
},
"icu:ConversationMerge--learn-more": {
"messageformat": "Learn More",
@@ -1253,11 +1257,11 @@
},
"icu:PhoneNumberDiscovery--notification--withSharedGroup": {
"messageformat": "{phoneNumber} belongs to {conversationTitle}. You're both members of {sharedGroup}.",
- "description": "Shown when we've discovered a phone number for a contact you've been communicating with."
+ "description": "(deleted 2023/01/11) Shown when we've discovered a phone number for a contact you've been communicating with."
},
"icu:PhoneNumberDiscovery--notification--noSharedGroup": {
"messageformat": "{phoneNumber} belongs to {conversationTitle}",
- "description": "Shown when we've discovered a phone number for a contact you've been communicating with, but you have no shared groups."
+ "description": "(deleted 2023/01/11) Shown when we've discovered a phone number for a contact you've been communicating with, but you have no shared groups."
},
"quoteThumbnailAlt": {
"message": "Thumbnail of image from quoted message",
diff --git a/images/icons/v2/merge-16.svg b/images/icons/v2/merge-16.svg
new file mode 100644
index 00000000000..35e7496d426
--- /dev/null
+++ b/images/icons/v2/merge-16.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/stylesheets/components/SystemMessage.scss b/stylesheets/components/SystemMessage.scss
index bb63dfd169a..2f265af108b 100644
--- a/stylesheets/components/SystemMessage.scss
+++ b/stylesheets/components/SystemMessage.scss
@@ -281,6 +281,13 @@
'../images/icons/v2/credit-card-16.svg'
);
}
+
+ &--icon-merge::before {
+ @include system-message-icon(
+ '../images/icons/v2/merge-16.svg',
+ '../images/icons/v2/merge-16.svg'
+ );
+ }
}
&--error {
diff --git a/ts/ConversationController.ts b/ts/ConversationController.ts
index 0a1cc50a9f2..dbeb61bf6cd 100644
--- a/ts/ConversationController.ts
+++ b/ts/ConversationController.ts
@@ -49,8 +49,7 @@ function applyChangeToConversation(
conversation: ConversationModel,
suggestedChange: Partial<
Pick
- >,
- disableDiscoveryNotification?: boolean
+ >
) {
const change = { ...suggestedChange };
@@ -84,9 +83,7 @@ function applyChangeToConversation(
conversation.updateUuid(change.uuid);
}
if (hasOwnProperty.call(change, 'e164')) {
- conversation.updateE164(change.e164, {
- disableDiscoveryNotification,
- });
+ conversation.updateE164(change.e164);
}
if (hasOwnProperty.call(change, 'pni')) {
conversation.updatePni(change.pni);
@@ -485,7 +482,6 @@ export class ConversationController {
const aci = providedAci ? UUID.cast(providedAci) : undefined;
const pni = providedPni ? UUID.cast(providedPni) : undefined;
- let targetConversationWasCreated = false;
const mergePromises: Array> = [];
if (!aci && !e164 && !pni) {
@@ -524,13 +520,9 @@ export class ConversationController {
`${logId}: No match for ${key}, applying to target conversation`
);
// Note: This line might erase a known e164 or PNI
- applyChangeToConversation(
- targetConversation,
- {
- [key]: value,
- },
- targetConversationWasCreated
- );
+ applyChangeToConversation(targetConversation, {
+ [key]: value,
+ });
} else {
unusedMatches.push(item);
}
@@ -578,7 +570,6 @@ export class ConversationController {
// If PNI match already has an ACI, then we need to create a new one
if (!targetConversation) {
targetConversation = this.getOrCreate(unused.value, 'private');
- targetConversationWasCreated = true;
log.info(
`${logId}: Match on ${key} already had ${unused.key}, ` +
`so created new target conversation - ${targetConversation.idForLogging()}`
@@ -588,13 +579,9 @@ export class ConversationController {
log.info(
`${logId}: Applying new value for ${unused.key} to target conversation`
);
- applyChangeToConversation(
- targetConversation,
- {
- [unused.key]: unused.value,
- },
- targetConversationWasCreated
- );
+ applyChangeToConversation(targetConversation, {
+ [unused.key]: unused.value,
+ });
});
unusedMatches = [];
@@ -633,20 +620,16 @@ export class ConversationController {
if ((key === 'pni' || key === 'e164') && match.get('uuid') === pni) {
change.uuid = undefined;
}
- applyChangeToConversation(match, change, targetConversationWasCreated);
+ applyChangeToConversation(match, change);
// Note: The PNI check here is just to be bulletproof; if we know a UUID is a PNI,
// then that should be put in the UUID field as well!
const willMerge =
!match.get('uuid') && !match.get('e164') && !match.get('pni');
- applyChangeToConversation(
- targetConversation,
- {
- [key]: value,
- },
- willMerge || targetConversationWasCreated
- );
+ applyChangeToConversation(targetConversation, {
+ [key]: value,
+ });
if (willMerge) {
log.warn(
@@ -666,13 +649,9 @@ export class ConversationController {
} else if (targetConversation && !targetConversation?.get(key)) {
// This is mostly for the situation where PNI was erased when updating e164
log.debug(`${logId}: Re-adding ${key} on target conversation`);
- applyChangeToConversation(
- targetConversation,
- {
- [key]: value,
- },
- targetConversationWasCreated
- );
+ applyChangeToConversation(targetConversation, {
+ [key]: value,
+ });
}
if (!targetConversation) {
@@ -739,7 +718,7 @@ export class ConversationController {
// `identifier` would resolve to uuid if we had both, so fix up e164
if (normalizedUuid && e164) {
- newConvo.updateE164(e164, { disableDiscoveryNotification: true });
+ newConvo.updateE164(e164);
}
return newConvo;
@@ -1131,7 +1110,7 @@ export class ConversationController {
const titleIsUseful = Boolean(
obsoleteTitleInfo && getTitleNoDefault(obsoleteTitleInfo)
);
- if (!fromPniSignature && obsoleteTitleInfo && titleIsUseful) {
+ if (obsoleteTitleInfo && titleIsUseful && !fromPniSignature) {
drop(current.addConversationMerge(obsoleteTitleInfo));
}
diff --git a/ts/components/ConversationList.tsx b/ts/components/ConversationList.tsx
index b1f8f34c2e3..932696f5b50 100644
--- a/ts/components/ConversationList.tsx
+++ b/ts/components/ConversationList.tsx
@@ -338,6 +338,7 @@ export function ConversationList({
'typingContactId',
'unblurredAvatarPath',
'unreadCount',
+ 'uuid',
]);
const { badges, title, unreadCount, lastMessage } = itemProps;
result = (
diff --git a/ts/components/conversation/ConversationMergeNotification.stories.tsx b/ts/components/conversation/ConversationMergeNotification.stories.tsx
index 61a642981fb..e32a6d63689 100644
--- a/ts/components/conversation/ConversationMergeNotification.stories.tsx
+++ b/ts/components/conversation/ConversationMergeNotification.stories.tsx
@@ -17,14 +17,25 @@ export default {
const createProps = (overrideProps: Partial = {}): PropsType => ({
i18n,
conversationTitle: overrideProps.conversationTitle || 'John Fire',
+ obsoleteConversationNumber:
+ overrideProps.obsoleteConversationNumber || '(555) 333-1111',
obsoleteConversationTitle:
- overrideProps.obsoleteConversationTitle || '(555) 333-1111',
+ overrideProps.obsoleteConversationTitle || 'John Obsolete',
});
export function Basic(): JSX.Element {
return ;
}
+export function WithNoObsoleteNumber(): JSX.Element {
+ return (
+
+ );
+}
+
export function WithNoObsoleteTitle(): JSX.Element {
return (
}
button={
obsoleteConversationTitle ? (
diff --git a/ts/components/conversation/PhoneNumberDiscoveryNotification.stories.tsx b/ts/components/conversation/PhoneNumberDiscoveryNotification.stories.tsx
deleted file mode 100644
index f782619a798..00000000000
--- a/ts/components/conversation/PhoneNumberDiscoveryNotification.stories.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2022 Signal Messenger, LLC
-// SPDX-License-Identifier: AGPL-3.0-only
-
-import * as React from 'react';
-
-import { setupI18n } from '../../util/setupI18n';
-import enMessages from '../../../_locales/en/messages.json';
-import type { PropsType } from './PhoneNumberDiscoveryNotification';
-import { PhoneNumberDiscoveryNotification } from './PhoneNumberDiscoveryNotification';
-
-const i18n = setupI18n('en', enMessages);
-
-export default {
- title: 'Components/Conversation/PhoneNumberDiscoveryNotification',
-};
-
-const createProps = (overrideProps: Partial = {}): PropsType => ({
- i18n,
- conversationTitle: overrideProps.conversationTitle || 'Mr. Fire',
- phoneNumber: overrideProps.phoneNumber || '+1 (000) 123-4567',
- sharedGroup: overrideProps.sharedGroup,
-});
-
-export function Basic(): JSX.Element {
- return ;
-}
-
-export function WithSharedGroup(): JSX.Element {
- return (
-
- );
-}
diff --git a/ts/components/conversation/PhoneNumberDiscoveryNotification.tsx b/ts/components/conversation/PhoneNumberDiscoveryNotification.tsx
deleted file mode 100644
index 6580aaa9ba0..00000000000
--- a/ts/components/conversation/PhoneNumberDiscoveryNotification.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2022 Signal Messenger, LLC
-// SPDX-License-Identifier: AGPL-3.0-only
-
-import React from 'react';
-
-import type { LocalizerType } from '../../types/Util';
-import { SystemMessage } from './SystemMessage';
-import { Emojify } from './Emojify';
-import { getStringForPhoneNumberDiscovery } from '../../util/getStringForPhoneNumberDiscovery';
-
-export type PropsDataType = {
- conversationTitle: string;
- phoneNumber: string;
- sharedGroup?: string;
-};
-export type PropsType = PropsDataType & {
- i18n: LocalizerType;
-};
-
-export function PhoneNumberDiscoveryNotification(
- props: PropsType
-): JSX.Element {
- const { conversationTitle, i18n, sharedGroup, phoneNumber } = props;
- const message = getStringForPhoneNumberDiscovery({
- conversationTitle,
- i18n,
- phoneNumber,
- sharedGroup,
- });
-
- return } />;
-}
diff --git a/ts/components/conversation/TimelineItem.tsx b/ts/components/conversation/TimelineItem.tsx
index c7a5111116d..f6ce1852fcc 100644
--- a/ts/components/conversation/TimelineItem.tsx
+++ b/ts/components/conversation/TimelineItem.tsx
@@ -50,8 +50,6 @@ import type { PropsType as PaymentEventNotificationPropsType } from './PaymentEv
import { PaymentEventNotification } from './PaymentEventNotification';
import type { PropsDataType as ConversationMergeNotificationPropsType } from './ConversationMergeNotification';
import { ConversationMergeNotification } from './ConversationMergeNotification';
-import type { PropsDataType as PhoneNumberDiscoveryNotificationPropsType } from './PhoneNumberDiscoveryNotification';
-import { PhoneNumberDiscoveryNotification } from './PhoneNumberDiscoveryNotification';
import type { FullJSXType } from '../Intl';
import { TimelineMessage } from './TimelineMessage';
@@ -119,10 +117,6 @@ type ConversationMergeNotificationType = {
type: 'conversationMerge';
data: ConversationMergeNotificationPropsType;
};
-type PhoneNumberDiscoveryNotificationType = {
- type: 'phoneNumberDiscovery';
- data: PhoneNumberDiscoveryNotificationPropsType;
-};
type PaymentEventType = {
type: 'paymentEvent';
data: Omit;
@@ -138,7 +132,6 @@ export type TimelineItemType = (
| GroupV1MigrationType
| GroupV2ChangeType
| MessageType
- | PhoneNumberDiscoveryNotificationType
| ProfileChangeNotificationType
| ResetSessionNotificationType
| SafetyNumberNotificationType
@@ -319,14 +312,6 @@ export class TimelineItem extends React.PureComponent {
i18n={i18n}
/>
);
- } else if (item.type === 'phoneNumberDiscovery') {
- notification = (
-
- );
} else if (item.type === 'resetSessionNotification') {
notification = (
diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts
index 1c636538888..664c47c9aa6 100644
--- a/ts/model-types.d.ts
+++ b/ts/model-types.d.ts
@@ -176,7 +176,6 @@ export type MessageAttributesType = {
| 'incoming'
| 'keychange'
| 'outgoing'
- | 'phone-number-discovery'
| 'profile-change'
| 'story'
| 'timer-notification'
@@ -209,9 +208,6 @@ export type MessageAttributesType = {
source?: string;
sourceUuid?: string;
};
- phoneNumberDiscovery?: {
- e164: string;
- };
conversationMerge?: {
renderInfo: ConversationRenderInfoType;
};
diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts
index 89e26521850..c1c2d1bb546 100644
--- a/ts/models/conversations.ts
+++ b/ts/models/conversations.ts
@@ -1912,14 +1912,7 @@ export class ConversationModel extends window.Backbone
};
}
- updateE164(
- e164?: string | null,
- {
- disableDiscoveryNotification,
- }: {
- disableDiscoveryNotification?: boolean;
- } = {}
- ): void {
+ updateE164(e164?: string | null): void {
const oldValue = this.get('e164');
if (e164 === oldValue) {
return;
@@ -1927,15 +1920,6 @@ export class ConversationModel extends window.Backbone
this.set('e164', e164 || undefined);
- // We just discovered a new phone number for this account. If we're not merging
- // then we'll add a standalone notification here.
- const haveSentMessage = Boolean(
- this.get('profileSharing') || this.get('sentMessageCount')
- );
- if (!oldValue && e164 && haveSentMessage && !disableDiscoveryNotification) {
- void this.addPhoneNumberDiscovery(e164);
- }
-
// This user changed their phone number
if (oldValue && e164) {
void this.addChangeNumberNotification(oldValue, e164);
@@ -3083,43 +3067,6 @@ export class ConversationModel extends window.Backbone
});
}
- async addPhoneNumberDiscovery(e164: string): Promise {
- log.info(
- `addPhoneNumberDiscovery/${this.idForLogging()}: Adding for ${e164}`
- );
-
- const timestamp = Date.now();
- const message: MessageAttributesType = {
- id: generateGuid(),
- conversationId: this.id,
- type: 'phone-number-discovery',
- sent_at: timestamp,
- timestamp,
- received_at: window.Signal.Util.incrementMessageCounter(),
- received_at_ms: timestamp,
- phoneNumberDiscovery: {
- e164,
- },
- readStatus: ReadStatus.Read,
- seenStatus: SeenStatus.Unseen,
- schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY,
- };
-
- const id = await window.Signal.Data.saveMessage(message, {
- ourUuid: window.textsecure.storage.user.getCheckedUuid().toString(),
- forceSave: true,
- });
- const model = window.MessageController.register(
- id,
- new window.Whisper.Message({
- ...message,
- id,
- })
- );
-
- this.trigger('newmessage', model);
- }
-
async addConversationMerge(
renderInfo: ConversationRenderInfoType
): Promise {
@@ -4845,7 +4792,6 @@ export class ConversationModel extends window.Backbone
// same before/after string, even if someone is moving from just first name to
// first/last name in their profile data.
const nameChanged = oldName !== newName;
-
if (!isMe(this.attributes) && hadPreviousName && nameChanged) {
const change = {
type: 'name',
@@ -4902,8 +4848,10 @@ export class ConversationModel extends window.Backbone
profileKey: string | undefined,
{ viaStorageServiceSync = false } = {}
): Promise {
+ const oldProfileKey = this.get('profileKey');
+
// profileKey is a string so we can compare it directly
- if (this.get('profileKey') !== profileKey) {
+ if (oldProfileKey !== profileKey) {
log.info(
`Setting sealedSender to UNKNOWN for conversation ${this.idForLogging()}`
);
diff --git a/ts/models/messages.ts b/ts/models/messages.ts
index 57a100aef64..5891ed6f77d 100644
--- a/ts/models/messages.ts
+++ b/ts/models/messages.ts
@@ -115,7 +115,6 @@ import {
isVerifiedChange,
processBodyRanges,
isConversationMerge,
- isPhoneNumberDiscovery,
} from '../state/selectors/message';
import {
isInCall,
@@ -174,8 +173,7 @@ import { GiftBadgeStates } from '../components/conversation/Message';
import { downloadAttachment } from '../util/downloadAttachment';
import type { StickerWithHydratedData } from '../types/Stickers';
import { getStringForConversationMerge } from '../util/getStringForConversationMerge';
-import { getStringForPhoneNumberDiscovery } from '../util/getStringForPhoneNumberDiscovery';
-import { getTitle, renderNumber } from '../util/getTitle';
+import { getTitleNoDefault, getNumber } from '../util/getTitle';
import dataInterface from '../sql/Client';
function isSameUuid(
@@ -409,7 +407,6 @@ export class MessageModel extends window.Backbone.Model {
!isGroupV1Migration(attributes) &&
!isGroupV2Change(attributes) &&
!isKeyChange(attributes) &&
- !isPhoneNumberDiscovery(attributes) &&
!isProfileChange(attributes) &&
!isUniversalTimerNotification(attributes) &&
!isUnsupportedMessage(attributes) &&
@@ -499,7 +496,10 @@ export class MessageModel extends window.Backbone.Model {
return {
text: getStringForConversationMerge({
- obsoleteConversationTitle: getTitle(
+ obsoleteConversationTitle: getTitleNoDefault(
+ attributes.conversationMerge.renderInfo
+ ),
+ obsoleteConversationNumber: getNumber(
attributes.conversationMerge.renderInfo
),
conversationTitle: conversation.getTitle(),
@@ -508,24 +508,6 @@ export class MessageModel extends window.Backbone.Model {
};
}
- if (isPhoneNumberDiscovery(attributes)) {
- const conversation = this.getConversation();
- strictAssert(conversation, 'getNotificationData/isPhoneNumberDiscovery');
- strictAssert(
- attributes.phoneNumberDiscovery,
- 'getNotificationData/isPhoneNumberDiscovery/phoneNumberDiscovery'
- );
-
- return {
- text: getStringForPhoneNumberDiscovery({
- phoneNumber: renderNumber(attributes.phoneNumberDiscovery.e164),
- conversationTitle: conversation.getTitle(),
- sharedGroup: conversation.get('sharedGroupNames')?.[0],
- i18n: window.i18n,
- }),
- };
- }
-
if (isChatSessionRefreshed(attributes)) {
return {
emoji: '🔁',
@@ -1219,7 +1201,6 @@ export class MessageModel extends window.Backbone.Model {
const isUniversalTimerNotificationValue =
isUniversalTimerNotification(attributes);
const isConversationMergeValue = isConversationMerge(attributes);
- const isPhoneNumberDiscoveryValue = isPhoneNumberDiscovery(attributes);
const isPayment = messageHasPaymentEvent(attributes);
@@ -1251,8 +1232,7 @@ export class MessageModel extends window.Backbone.Model {
isKeyChangeValue ||
isProfileChangeValue ||
isUniversalTimerNotificationValue ||
- isConversationMergeValue ||
- isPhoneNumberDiscoveryValue;
+ isConversationMergeValue;
return !hasSomethingToDisplay;
}
diff --git a/ts/sql/migrations/73-remove-phone-number-discovery.ts b/ts/sql/migrations/73-remove-phone-number-discovery.ts
new file mode 100644
index 00000000000..ee3766ad1bb
--- /dev/null
+++ b/ts/sql/migrations/73-remove-phone-number-discovery.ts
@@ -0,0 +1,112 @@
+// Copyright 2023 Signal Messenger, LLC
+// SPDX-License-Identifier: AGPL-3.0-only
+
+import type { Database } from '@signalapp/better-sqlite3';
+
+import type { LoggerType } from '../../types/Logging';
+
+export default function updateToSchemaVersion73(
+ currentVersion: number,
+ db: Database,
+ logger: LoggerType
+): void {
+ if (currentVersion >= 73) {
+ return;
+ }
+
+ db.transaction(() => {
+ db.exec(
+ `
+ --- Delete deprecated notifications
+ DELETE FROM messages WHERE type IS 'phone-number-discovery';
+
+ --- These will be re-added below
+ DROP INDEX messages_preview;
+ DROP INDEX messages_activity;
+ DROP INDEX message_user_initiated;
+
+ --- These will also be re-added below
+ ALTER TABLE messages DROP COLUMN shouldAffectActivity;
+ ALTER TABLE messages DROP COLUMN shouldAffectPreview;
+ ALTER TABLE messages DROP COLUMN isUserInitiatedMessage;
+
+ --- Note: These generated columns were originally introduced in migration 71, and
+ --- are mostly the same
+
+ --- (change: removed phone-number-discovery)
+ ALTER TABLE messages
+ ADD COLUMN shouldAffectActivity INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ );
+
+ --- (change: removed phone-number-discovery
+ --- (now matches the above list)
+ ALTER TABLE messages
+ ADD COLUMN shouldAffectPreview INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ );
+
+ --- Note: This list only differs from the above on these types:
+ --- group-v2-change
+
+ --- (change: removed phone-number-discovery
+ ALTER TABLE messages
+ ADD COLUMN isUserInitiatedMessage INTEGER
+ GENERATED ALWAYS AS (
+ type IS NULL
+ OR
+ type NOT IN (
+ 'change-number-notification',
+ 'conversation-merge',
+ 'group-v1-migration',
+ 'group-v2-change',
+ 'keychange',
+ 'message-history-unsynced',
+ 'profile-change',
+ 'story',
+ 'universal-timer-notification',
+ 'verified-change'
+ )
+ );
+
+ CREATE INDEX messages_preview ON messages
+ (conversationId, shouldAffectPreview, isGroupLeaveEventFromOther, expiresAt, received_at, sent_at);
+
+ CREATE INDEX messages_activity ON messages
+ (conversationId, shouldAffectActivity, isTimerChangeFromSync, isGroupLeaveEventFromOther, received_at, sent_at);
+
+ CREATE INDEX message_user_initiated ON messages (isUserInitiatedMessage);
+ `
+ );
+
+ db.pragma('user_version = 73');
+ })();
+
+ logger.info('updateToSchemaVersion73: success!');
+}
diff --git a/ts/sql/migrations/index.ts b/ts/sql/migrations/index.ts
index b85de24b92e..1454715876a 100644
--- a/ts/sql/migrations/index.ts
+++ b/ts/sql/migrations/index.ts
@@ -48,6 +48,7 @@ import updateToSchemaVersion69 from './69-group-call-ring-cancellations';
import updateToSchemaVersion70 from './70-story-reply-index';
import updateToSchemaVersion71 from './71-merge-notifications';
import updateToSchemaVersion72 from './72-optimize-call-id-message-lookup';
+import updateToSchemaVersion73 from './73-remove-phone-number-discovery';
function updateToSchemaVersion1(
currentVersion: number,
@@ -1965,6 +1966,7 @@ export const SCHEMA_VERSIONS = [
updateToSchemaVersion70,
updateToSchemaVersion71,
updateToSchemaVersion72,
+ updateToSchemaVersion73,
];
export function updateSchema(db: Database, logger: LoggerType): void {
diff --git a/ts/state/selectors/message.ts b/ts/state/selectors/message.ts
index e7ea6c2a1af..5c77ce6dceb 100644
--- a/ts/state/selectors/message.ts
+++ b/ts/state/selectors/message.ts
@@ -34,7 +34,6 @@ import type { PropsDataType as GroupV1MigrationPropsType } from '../../component
import type { PropsDataType as DeliveryIssuePropsType } from '../../components/conversation/DeliveryIssueNotification';
import type { PropsType as PaymentEventNotificationPropsType } from '../../components/conversation/PaymentEventNotification';
import type { PropsDataType as ConversationMergePropsType } from '../../components/conversation/ConversationMergeNotification';
-import type { PropsDataType as PhoneNumberDiscoveryPropsType } from '../../components/conversation/PhoneNumberDiscoveryNotification';
import type {
PropsData as GroupNotificationProps,
ChangeType,
@@ -119,7 +118,7 @@ import { calculateExpirationTimestamp } from '../../util/expirationTimer';
import { isSignalConversation } from '../../util/isSignalConversation';
import type { AnyPaymentEvent } from '../../types/Payment';
import { isPaymentNotificationEvent } from '../../types/Payment';
-import { getTitle, renderNumber } from '../../util/getTitle';
+import { getTitleNoDefault, getNumber } from '../../util/getTitle';
export { isIncoming, isOutgoing, isStory };
@@ -895,13 +894,6 @@ export function getPropsForBubble(
timestamp,
};
}
- if (isPhoneNumberDiscovery(message)) {
- return {
- type: 'phoneNumberDiscovery',
- data: getPhoneNumberDiscovery(message, options),
- timestamp,
- };
- }
if (
messageHasPaymentEvent(message) &&
@@ -1422,37 +1414,16 @@ export function getPropsForConversationMerge(
const conversation = getConversation(message, conversationSelector);
const conversationTitle = conversation.title;
- const { type, e164 } = conversationMerge.renderInfo;
- const obsoleteConversationTitle = e164 ? getTitle({ type, e164 }) : undefined;
+ const { renderInfo } = conversationMerge;
+ const obsoleteConversationTitle = getTitleNoDefault(renderInfo);
+ const obsoleteConversationNumber = getNumber(renderInfo);
return {
conversationTitle,
obsoleteConversationTitle,
+ obsoleteConversationNumber,
};
}
-export function isPhoneNumberDiscovery(
- message: MessageWithUIFieldsType
-): boolean {
- return message.type === 'phone-number-discovery';
-}
-export function getPhoneNumberDiscovery(
- message: MessageWithUIFieldsType,
- { conversationSelector }: GetPropsForBubbleOptions
-): PhoneNumberDiscoveryPropsType {
- const { phoneNumberDiscovery } = message;
- if (!phoneNumberDiscovery) {
- throw new Error(
- 'getPhoneNumberDiscovery: message is missing phoneNumberDiscovery!'
- );
- }
-
- const conversation = getConversation(message, conversationSelector);
- const conversationTitle = conversation.title;
- const sharedGroup = conversation.sharedGroupNames[0];
- const phoneNumber = renderNumber(phoneNumberDiscovery.e164);
-
- return { conversationTitle, sharedGroup, phoneNumber };
-}
// Delivery Issue
diff --git a/ts/test-mock/pnp/learn_test.ts b/ts/test-mock/pnp/learn_test.ts
deleted file mode 100644
index 9e7526e35c9..00000000000
--- a/ts/test-mock/pnp/learn_test.ts
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2022 Signal Messenger, LLC
-// SPDX-License-Identifier: AGPL-3.0-only
-
-import { assert } from 'chai';
-import { UUIDKind, Proto, StorageState } from '@signalapp/mock-server';
-import type { PrimaryDevice } from '@signalapp/mock-server';
-import createDebug from 'debug';
-
-import * as durations from '../../util/durations';
-import { Bootstrap } from '../bootstrap';
-import type { App } from '../bootstrap';
-
-export const debug = createDebug('mock:test:pni-signature');
-
-describe('pnp/learn', function needsName() {
- this.timeout(durations.MINUTE);
-
- let bootstrap: Bootstrap;
- let app: App;
- let contactA: PrimaryDevice;
-
- beforeEach(async () => {
- bootstrap = new Bootstrap();
- await bootstrap.init();
-
- const { server, phone } = bootstrap;
-
- contactA = await server.createPrimaryDevice({
- profileName: 'contactA',
- });
-
- let state = StorageState.getEmpty();
-
- state = state.updateAccount({
- profileKey: phone.profileKey.serialize(),
- e164: phone.device.number,
- });
-
- state = state.addContact(
- contactA,
- {
- whitelisted: false,
- identityKey: contactA.getPublicKey(UUIDKind.ACI).serialize(),
- serviceE164: undefined,
- givenName: 'ContactA',
- },
- UUIDKind.ACI
- );
-
- // Just to make PNI Contact visible in the left pane
- state = state.pin(contactA, UUIDKind.ACI);
-
- await phone.setStorageState(state);
-
- app = await bootstrap.link();
- });
-
- afterEach(async function after() {
- if (this.currentTest?.state !== 'passed') {
- await bootstrap.saveLogs(app);
- }
-
- await app.close();
- await bootstrap.teardown();
- });
-
- it('shows Learned Number notification if we find out number later', async () => {
- const { desktop, phone } = bootstrap;
-
- const window = await app.getWindow();
-
- debug('Open conversation with contactA');
- {
- const leftPane = window.locator('.left-pane-wrapper');
-
- await leftPane
- .locator('_react=ConversationListItem[title = "ContactA"]')
- .click();
-
- await window.locator('.module-conversation-hero').waitFor();
- }
-
- debug('Verify starting state');
- {
- // No messages
- const messages = window.locator('.module-message__text');
- assert.strictEqual(await messages.count(), 0, 'message count');
-
- // No notifications
- const notifications = window.locator('.SystemMessage');
- assert.strictEqual(await notifications.count(), 0, 'notification count');
- }
-
- debug('Send message to contactA');
- {
- const composeArea = window.locator(
- '.composition-area-wrapper, .conversation .ConversationView'
- );
- const compositionInput = composeArea.locator('_react=CompositionInput');
-
- await compositionInput.type('message to contactA');
- await compositionInput.press('Enter');
- }
-
- debug('Wait for the message to contactA');
- {
- const { source, body } = await contactA.waitForMessage();
-
- assert.strictEqual(
- source,
- desktop,
- 'first message must have valid source'
- );
- assert.strictEqual(
- body,
- 'message to contactA',
- 'message must have correct body'
- );
- }
-
- debug('Add phone number to contactA via storage service');
- {
- const state = await phone.expectStorageState('consistency check');
- const updated = await phone.setStorageState(
- state
- .removeRecord(
- item =>
- item.record.contact?.serviceUuid ===
- contactA.device.getUUIDByKind(UUIDKind.ACI)
- )
- .addContact(
- contactA,
- {
- identityState: Proto.ContactRecord.IdentityState.DEFAULT,
- whitelisted: true,
- identityKey: contactA.getPublicKey(UUIDKind.ACI).serialize(),
- givenName: 'ContactA',
- serviceE164: contactA.device.number,
- },
- UUIDKind.ACI
- )
- );
-
- const updatedStorageVersion = updated.version;
-
- await phone.sendFetchStorage({
- timestamp: bootstrap.getTimestamp(),
- });
-
- await app.waitForManifestVersion(updatedStorageVersion);
- }
-
- debug('Verify final state');
- {
- // One outgoing message
- const messages = window.locator('.module-message__text');
- assert.strictEqual(await messages.count(), 1, 'messages');
-
- // One 'learned number' notification
- const notifications = window.locator('.SystemMessage');
- assert.strictEqual(await notifications.count(), 1, 'notifications');
-
- const first = await notifications.first();
- assert.match(await first.innerText(), /belongs to ContactA$/);
- }
- });
-
- it('Does not show Learned Number notification if no sent, not in allowlist', async () => {
- const { phone } = bootstrap;
-
- const window = await app.getWindow();
-
- debug('Open conversation with contactA');
- {
- const leftPane = window.locator('.left-pane-wrapper');
-
- await leftPane
- .locator('_react=ConversationListItem[title = "ContactA"]')
- .click();
-
- await window.locator('.module-conversation-hero').waitFor();
- }
-
- debug('Verify starting state');
- {
- // No messages
- const messages = window.locator('.module-message__text');
- assert.strictEqual(await messages.count(), 0, 'message count');
-
- // No notifications
- const notifications = window.locator('.SystemMessage');
- assert.strictEqual(await notifications.count(), 0, 'notification count');
- }
-
- debug('Add phone number to contactA via storage service');
- {
- const state = await phone.expectStorageState('consistency check');
- const updated = await phone.setStorageState(
- state
- .removeRecord(
- item =>
- item.record.contact?.serviceUuid ===
- contactA.device.getUUIDByKind(UUIDKind.ACI)
- )
- .addContact(
- contactA,
- {
- identityState: Proto.ContactRecord.IdentityState.DEFAULT,
- whitelisted: false,
- identityKey: contactA.getPublicKey(UUIDKind.ACI).serialize(),
- givenName: 'ContactA',
- serviceE164: contactA.device.number,
- },
- UUIDKind.ACI
- )
- );
-
- const updatedStorageVersion = updated.version;
-
- await phone.sendFetchStorage({
- timestamp: bootstrap.getTimestamp(),
- });
-
- await app.waitForManifestVersion(updatedStorageVersion);
- }
-
- debug('Verify final state');
- {
- // No messages
- const messages = window.locator('.module-message__text');
- assert.strictEqual(await messages.count(), 0, 'messages');
-
- // No 'learned number' notification
- const notifications = window.locator('.SystemMessage');
- assert.strictEqual(await notifications.count(), 0, 'notifications');
- }
- });
-});
diff --git a/ts/test-mock/pnp/merge_test.ts b/ts/test-mock/pnp/merge_test.ts
index 959d7829685..517272949fd 100644
--- a/ts/test-mock/pnp/merge_test.ts
+++ b/ts/test-mock/pnp/merge_test.ts
@@ -220,7 +220,7 @@ describe('pnp/merge', function needsName() {
const first = await notifications.first();
assert.match(
await first.innerText(),
- /and ACI Contact are the same account. Your message history for both chats are here./
+ /Your message history with ACI Contact and their number .* has been merged./
);
}
});
diff --git a/ts/test-mock/pnp/pni_signature_test.ts b/ts/test-mock/pnp/pni_signature_test.ts
index bbfd752245f..67485998535 100644
--- a/ts/test-mock/pnp/pni_signature_test.ts
+++ b/ts/test-mock/pnp/pni_signature_test.ts
@@ -339,6 +339,7 @@ describe('pnp/PNI Signature', function needsName() {
}
debug('Verify final state');
+
{
const newState = await phone.waitForStorageState({
after: state,
diff --git a/ts/util/getStringForConversationMerge.ts b/ts/util/getStringForConversationMerge.ts
index 4bcd695ef3f..a2a424795e1 100644
--- a/ts/util/getStringForConversationMerge.ts
+++ b/ts/util/getStringForConversationMerge.ts
@@ -5,19 +5,28 @@ import type { LocalizerType } from '../types/Util';
export function getStringForConversationMerge({
obsoleteConversationTitle,
+ obsoleteConversationNumber,
conversationTitle,
i18n,
}: {
obsoleteConversationTitle: string | undefined;
+ obsoleteConversationNumber: string | undefined;
conversationTitle: string;
i18n: LocalizerType;
}): string {
if (!obsoleteConversationTitle) {
- return i18n('icu:ConversationMerge--notification--no-e164', {
+ return i18n('icu:ConversationMerge--notification--no-title', {
conversationTitle,
});
}
+ if (obsoleteConversationNumber) {
+ return i18n('icu:ConversationMerge--notification--with-e164', {
+ conversationTitle,
+ obsoleteConversationNumber,
+ });
+ }
+
return i18n('icu:ConversationMerge--notification', {
obsoleteConversationTitle,
conversationTitle,
diff --git a/ts/util/getStringForPhoneNumberDiscovery.ts b/ts/util/getStringForPhoneNumberDiscovery.ts
deleted file mode 100644
index d8291d926b8..00000000000
--- a/ts/util/getStringForPhoneNumberDiscovery.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 Signal Messenger, LLC
-// SPDX-License-Identifier: AGPL-3.0-only
-
-import type { LocalizerType } from '../types/Util';
-
-export function getStringForPhoneNumberDiscovery({
- phoneNumber,
- i18n,
- conversationTitle,
- sharedGroup,
-}: {
- phoneNumber: string;
- i18n: LocalizerType;
- conversationTitle: string;
- sharedGroup?: string;
-}): string {
- if (sharedGroup) {
- return i18n('icu:PhoneNumberDiscovery--notification--withSharedGroup', {
- phoneNumber,
- conversationTitle,
- sharedGroup,
- });
- }
-
- return i18n('icu:PhoneNumberDiscovery--notification--noSharedGroup', {
- phoneNumber,
- conversationTitle,
- });
-}