Fix rendering of group joins and remove checkServiceIdEquivalence
This commit is contained in:
parent
214fae0c6e
commit
a1f0afdae8
12 changed files with 108 additions and 65 deletions
|
@ -50,13 +50,6 @@ const renderContact: SmartContactRendererType<JSX.Element> = (
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
function checkServiceIdEquivalence(
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
): boolean {
|
|
||||||
return Boolean(left && right && contactMap[left] === contactMap[right]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderChange = (
|
const renderChange = (
|
||||||
change: GroupV2ChangeType,
|
change: GroupV2ChangeType,
|
||||||
{
|
{
|
||||||
|
@ -79,7 +72,6 @@ const renderChange = (
|
||||||
blockGroupLinkRequests={action('blockGroupLinkRequests')}
|
blockGroupLinkRequests={action('blockGroupLinkRequests')}
|
||||||
conversationId="some-conversation-id"
|
conversationId="some-conversation-id"
|
||||||
change={change}
|
change={change}
|
||||||
checkServiceIdEquivalence={checkServiceIdEquivalence}
|
|
||||||
groupBannedMemberships={groupBannedMemberships}
|
groupBannedMemberships={groupBannedMemberships}
|
||||||
groupMemberships={groupMemberships}
|
groupMemberships={groupMemberships}
|
||||||
groupName={groupName}
|
groupName={groupName}
|
||||||
|
@ -615,7 +607,39 @@ export function MemberAddFromInvited(): JSX.Element {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})}
|
})}
|
||||||
ACI accepts PNI invite:
|
ACI accepts PNI invite (X joined the group)
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_PNI,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-invite',
|
||||||
|
aci: OUR_ACI,
|
||||||
|
pni: OUR_PNI,
|
||||||
|
inviter: CONTACT_B,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: OUR_PNI,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-invite',
|
||||||
|
aci: OUR_ACI,
|
||||||
|
pni: OUR_PNI,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
{renderChange({
|
||||||
|
from: CONTACT_A_PNI,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-invite',
|
||||||
|
aci: CONTACT_A,
|
||||||
|
pni: CONTACT_A_PNI,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
ACI accepts PNI invite, the old way (X added X to group)
|
||||||
{renderChange({
|
{renderChange({
|
||||||
from: OUR_PNI,
|
from: OUR_PNI,
|
||||||
details: [
|
details: [
|
||||||
|
|
|
@ -49,10 +49,6 @@ export type PropsActionsType = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsHousekeepingType = {
|
export type PropsHousekeepingType = {
|
||||||
checkServiceIdEquivalence(
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
): boolean;
|
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
renderContact: SmartContactRendererType<JSX.Element>;
|
renderContact: SmartContactRendererType<JSX.Element>;
|
||||||
};
|
};
|
||||||
|
@ -297,7 +293,6 @@ export function GroupV2Change(props: PropsType): ReactElement {
|
||||||
areWeAdmin,
|
areWeAdmin,
|
||||||
blockGroupLinkRequests,
|
blockGroupLinkRequests,
|
||||||
change,
|
change,
|
||||||
checkServiceIdEquivalence,
|
|
||||||
conversationId,
|
conversationId,
|
||||||
groupBannedMemberships,
|
groupBannedMemberships,
|
||||||
groupMemberships,
|
groupMemberships,
|
||||||
|
@ -311,7 +306,6 @@ export function GroupV2Change(props: PropsType): ReactElement {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderChange<JSX.Element>(change, {
|
{renderChange<JSX.Element>(change, {
|
||||||
checkServiceIdEquivalence,
|
|
||||||
i18n,
|
i18n,
|
||||||
ourAci,
|
ourAci,
|
||||||
ourPni,
|
ourPni,
|
||||||
|
|
|
@ -361,7 +361,6 @@ const renderItem = ({
|
||||||
isNextItemCallingNotification={false}
|
isNextItemCallingNotification={false}
|
||||||
theme={ThemeType.light}
|
theme={ThemeType.light}
|
||||||
platform="darwin"
|
platform="darwin"
|
||||||
checkServiceIdEquivalence={() => false}
|
|
||||||
containerElementRef={containerElementRef}
|
containerElementRef={containerElementRef}
|
||||||
containerWidthBreakpoint={containerWidthBreakpoint}
|
containerWidthBreakpoint={containerWidthBreakpoint}
|
||||||
conversationId=""
|
conversationId=""
|
||||||
|
|
|
@ -69,7 +69,6 @@ const getDefaultProps = () => ({
|
||||||
toggleSelectMessage: action('toggleSelectMessage'),
|
toggleSelectMessage: action('toggleSelectMessage'),
|
||||||
reactToMessage: action('reactToMessage'),
|
reactToMessage: action('reactToMessage'),
|
||||||
checkForAccount: action('checkForAccount'),
|
checkForAccount: action('checkForAccount'),
|
||||||
checkServiceIdEquivalence: () => false,
|
|
||||||
clearTargetedMessage: action('clearTargetedMessage'),
|
clearTargetedMessage: action('clearTargetedMessage'),
|
||||||
setMessageToEdit: action('setMessageToEdit'),
|
setMessageToEdit: action('setMessageToEdit'),
|
||||||
setQuoteByMessageId: action('setQuoteByMessageId'),
|
setQuoteByMessageId: action('setQuoteByMessageId'),
|
||||||
|
|
|
@ -61,7 +61,6 @@ import {
|
||||||
type MessageRequestResponseNotificationData,
|
type MessageRequestResponseNotificationData,
|
||||||
} from './MessageRequestResponseNotification';
|
} from './MessageRequestResponseNotification';
|
||||||
import type { MessageRequestState } from './MessageRequestActionsConfirmation';
|
import type { MessageRequestState } from './MessageRequestActionsConfirmation';
|
||||||
import type { ServiceIdString } from '../../types/ServiceId';
|
|
||||||
|
|
||||||
type CallHistoryType = {
|
type CallHistoryType = {
|
||||||
type: 'callHistory';
|
type: 'callHistory';
|
||||||
|
@ -173,10 +172,6 @@ export type TimelineItemType = (
|
||||||
) & { timestamp: number };
|
) & { timestamp: number };
|
||||||
|
|
||||||
type PropsLocalType = {
|
type PropsLocalType = {
|
||||||
checkServiceIdEquivalence(
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
): boolean;
|
|
||||||
containerElementRef: RefObject<HTMLElement>;
|
containerElementRef: RefObject<HTMLElement>;
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
item?: TimelineItemType;
|
item?: TimelineItemType;
|
||||||
|
|
|
@ -37,10 +37,6 @@ export type RenderOptionsType<T extends string | JSX.Element> = {
|
||||||
ourAci: AciString | undefined;
|
ourAci: AciString | undefined;
|
||||||
ourPni: PniString | undefined;
|
ourPni: PniString | undefined;
|
||||||
renderContact: SmartContactRendererType<T>;
|
renderContact: SmartContactRendererType<T>;
|
||||||
checkServiceIdEquivalence(
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
): boolean;
|
|
||||||
renderIntl: StringRendererType<T>;
|
renderIntl: StringRendererType<T>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +83,6 @@ function renderChangeDetail<T extends string | JSX.Element>(
|
||||||
options: RenderOptionsType<T>
|
options: RenderOptionsType<T>
|
||||||
): string | T | ReadonlyArray<string | T> {
|
): string | T | ReadonlyArray<string | T> {
|
||||||
const {
|
const {
|
||||||
checkServiceIdEquivalence,
|
|
||||||
from,
|
from,
|
||||||
i18n: localizer,
|
i18n: localizer,
|
||||||
ourAci,
|
ourAci,
|
||||||
|
@ -301,11 +296,14 @@ function renderChangeDetail<T extends string | JSX.Element>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (detail.type === 'member-add-from-invite') {
|
if (detail.type === 'member-add-from-invite') {
|
||||||
const { aci, inviter } = detail;
|
const { aci, inviter, pni } = detail;
|
||||||
const weAreJoiner = isOurServiceId(aci);
|
const weAreJoiner = isOurServiceId(aci);
|
||||||
const weAreInviter = isOurServiceId(inviter);
|
const weAreInviter = isOurServiceId(inviter);
|
||||||
|
|
||||||
if (!from || !checkServiceIdEquivalence(from, aci)) {
|
const fromPni = pni && from === pni;
|
||||||
|
const fromAci = from === aci;
|
||||||
|
|
||||||
|
if (!from || (!fromPni && !fromAci)) {
|
||||||
if (weAreJoiner) {
|
if (weAreJoiner) {
|
||||||
// They can't be the same, no fromYou check here
|
// They can't be the same, no fromYou check here
|
||||||
if (from) {
|
if (from) {
|
||||||
|
@ -433,7 +431,7 @@ function renderChangeDetail<T extends string | JSX.Element>(
|
||||||
memberName: renderContact(aci),
|
memberName: renderContact(aci),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (from && fromYou) {
|
if (from && from === aci) {
|
||||||
return i18n('icu:GroupV2--member-remove--other--self', {
|
return i18n('icu:GroupV2--member-remove--other--self', {
|
||||||
memberName: renderContact(from),
|
memberName: renderContact(from),
|
||||||
});
|
});
|
||||||
|
|
|
@ -149,6 +149,7 @@ type GroupV2MemberAddChangeType = {
|
||||||
type GroupV2MemberAddFromInviteChangeType = {
|
type GroupV2MemberAddFromInviteChangeType = {
|
||||||
type: 'member-add-from-invite';
|
type: 'member-add-from-invite';
|
||||||
aci: AciString;
|
aci: AciString;
|
||||||
|
pni?: PniString;
|
||||||
inviter?: AciString;
|
inviter?: AciString;
|
||||||
};
|
};
|
||||||
type GroupV2MemberAddFromLinkChangeType = {
|
type GroupV2MemberAddFromLinkChangeType = {
|
||||||
|
@ -4430,6 +4431,7 @@ function extractDiffs({
|
||||||
details.push({
|
details.push({
|
||||||
type: 'member-add-from-invite',
|
type: 'member-add-from-invite',
|
||||||
aci,
|
aci,
|
||||||
|
pni,
|
||||||
inviter: pendingMember.addedByUserId,
|
inviter: pendingMember.addedByUserId,
|
||||||
});
|
});
|
||||||
} else if (currentMember.joinedFromLink) {
|
} else if (currentMember.joinedFromLink) {
|
||||||
|
|
|
@ -1253,7 +1253,13 @@ export class BackupExportStream extends Readable {
|
||||||
update.groupMemberAddedUpdate = innerUpdate;
|
update.groupMemberAddedUpdate = innerUpdate;
|
||||||
updates.push(update);
|
updates.push(update);
|
||||||
} else if (type === 'member-add-from-invite') {
|
} else if (type === 'member-add-from-invite') {
|
||||||
if (from && checkServiceIdEquivalence(from, detail.aci)) {
|
const { aci, pni } = detail;
|
||||||
|
if (
|
||||||
|
from &&
|
||||||
|
((pni && from === pni) ||
|
||||||
|
(aci && from === aci) ||
|
||||||
|
checkServiceIdEquivalence(from, aci))
|
||||||
|
) {
|
||||||
const innerUpdate = new Backups.GroupInvitationAcceptedUpdate();
|
const innerUpdate = new Backups.GroupInvitationAcceptedUpdate();
|
||||||
innerUpdate.newMemberAci = this.aciToBytes(detail.aci);
|
innerUpdate.newMemberAci = this.aciToBytes(detail.aci);
|
||||||
if (detail.inviter) {
|
if (detail.inviter) {
|
||||||
|
|
|
@ -931,24 +931,6 @@ export const getConversationSelector = createSelector(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export type CheckServiceIdEquivalenceType = (
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
) => boolean;
|
|
||||||
export const getCheckServiceIdEquivalence = createSelector(
|
|
||||||
getConversationByAnyIdSelector,
|
|
||||||
(
|
|
||||||
getById: GetConversationByAnyIdSelectorType
|
|
||||||
): CheckServiceIdEquivalenceType => {
|
|
||||||
return (
|
|
||||||
left: ServiceIdString | undefined,
|
|
||||||
right: ServiceIdString | undefined
|
|
||||||
): boolean => {
|
|
||||||
return Boolean(left && right && getById(left) === getById(right));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const getConversationByIdSelector = createSelector(
|
export const getConversationByIdSelector = createSelector(
|
||||||
getConversationLookup,
|
getConversationLookup,
|
||||||
conversationLookup =>
|
conversationLookup =>
|
||||||
|
|
|
@ -21,10 +21,7 @@ import {
|
||||||
getTheme,
|
getTheme,
|
||||||
getPlatform,
|
getPlatform,
|
||||||
} from '../selectors/user';
|
} from '../selectors/user';
|
||||||
import {
|
import { getTargetedMessage } from '../selectors/conversations';
|
||||||
getTargetedMessage,
|
|
||||||
getCheckServiceIdEquivalence,
|
|
||||||
} from '../selectors/conversations';
|
|
||||||
import { useTimelineItem } from '../selectors/timeline';
|
import { useTimelineItem } from '../selectors/timeline';
|
||||||
import {
|
import {
|
||||||
areMessagesInSameGroup,
|
areMessagesInSameGroup,
|
||||||
|
@ -89,8 +86,6 @@ export const SmartTimelineItem = memo(function SmartTimelineItem(
|
||||||
const isTargeted = Boolean(
|
const isTargeted = Boolean(
|
||||||
targetedMessage && messageId === targetedMessage.id
|
targetedMessage && messageId === targetedMessage.id
|
||||||
);
|
);
|
||||||
const checkServiceIdEquivalence = useSelector(getCheckServiceIdEquivalence);
|
|
||||||
|
|
||||||
const isNextItemCallingNotification = nextItem?.type === 'callHistory';
|
const isNextItemCallingNotification = nextItem?.type === 'callHistory';
|
||||||
|
|
||||||
const shouldCollapseAbove = areMessagesInSameGroup(
|
const shouldCollapseAbove = areMessagesInSameGroup(
|
||||||
|
@ -180,7 +175,6 @@ export const SmartTimelineItem = memo(function SmartTimelineItem(
|
||||||
<TimelineItem
|
<TimelineItem
|
||||||
item={item}
|
item={item}
|
||||||
id={messageId}
|
id={messageId}
|
||||||
checkServiceIdEquivalence={checkServiceIdEquivalence}
|
|
||||||
containerElementRef={containerElementRef}
|
containerElementRef={containerElementRef}
|
||||||
containerWidthBreakpoint={containerWidthBreakpoint}
|
containerWidthBreakpoint={containerWidthBreakpoint}
|
||||||
conversationId={conversationId}
|
conversationId={conversationId}
|
||||||
|
|
|
@ -709,7 +709,40 @@ describe('backup/groupv2/notifications', () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
// ACI accepts PNI invite:
|
// ACI accepts PNI invite (X joined the group)
|
||||||
|
// These don't roundtrip; the PNI from is replaced with ACI. See next test below.
|
||||||
|
// createMessage({
|
||||||
|
// from: OUR_PNI,
|
||||||
|
// details: [
|
||||||
|
// {
|
||||||
|
// type: 'member-add-from-invite',
|
||||||
|
// aci: OUR_ACI,
|
||||||
|
// pni: OUR_PNI,
|
||||||
|
// inviter: CONTACT_B,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// createMessage({
|
||||||
|
// from: OUR_PNI,
|
||||||
|
// details: [
|
||||||
|
// {
|
||||||
|
// type: 'member-add-from-invite',
|
||||||
|
// aci: OUR_ACI,
|
||||||
|
// pni: OUR_PNI,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// createMessage({
|
||||||
|
// from: CONTACT_A_PNI,
|
||||||
|
// details: [
|
||||||
|
// {
|
||||||
|
// type: 'member-add-from-invite',
|
||||||
|
// aci: CONTACT_A,
|
||||||
|
// pni: CONTACT_A_PNI,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// ACI accepts PNI invite, the old way (X added X to group)
|
||||||
// These don't roundtrip; the PNI is replaced with ACI. See next test below.
|
// These don't roundtrip; the PNI is replaced with ACI. See next test below.
|
||||||
// createMessage({
|
// createMessage({
|
||||||
// from: OUR_PNI,
|
// from: OUR_PNI,
|
||||||
|
@ -813,8 +846,31 @@ describe('backup/groupv2/notifications', () => {
|
||||||
{ disableIncrement: true }
|
{ disableIncrement: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const before = [firstBefore, secondBefore, thirdBefore];
|
const fourthBefore = createMessage({
|
||||||
const after = [firstAfter, secondAfter, thirdAfter];
|
from: CONTACT_A_PNI,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-invite',
|
||||||
|
aci: CONTACT_A,
|
||||||
|
pni: CONTACT_A_PNI,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const fourthAfter = createMessage(
|
||||||
|
{
|
||||||
|
from: CONTACT_A,
|
||||||
|
details: [
|
||||||
|
{
|
||||||
|
type: 'member-add-from-invite',
|
||||||
|
aci: CONTACT_A,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ disableIncrement: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const before = [firstBefore, secondBefore, thirdBefore, fourthBefore];
|
||||||
|
const after = [firstAfter, secondAfter, thirdAfter, fourthAfter];
|
||||||
|
|
||||||
await asymmetricRoundtripHarness(before, after);
|
await asymmetricRoundtripHarness(before, after);
|
||||||
});
|
});
|
||||||
|
|
|
@ -143,12 +143,6 @@ export function getNotificationDataForMessage(
|
||||||
);
|
);
|
||||||
|
|
||||||
const changes = GroupChange.renderChange<string>(change, {
|
const changes = GroupChange.renderChange<string>(change, {
|
||||||
checkServiceIdEquivalence: (left, right) => {
|
|
||||||
return (
|
|
||||||
window.ConversationController.get(left) ===
|
|
||||||
window.ConversationController.get(right)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
i18n: window.i18n,
|
i18n: window.i18n,
|
||||||
ourAci: window.textsecure.storage.user.getCheckedAci(),
|
ourAci: window.textsecure.storage.user.getCheckedAci(),
|
||||||
ourPni: window.textsecure.storage.user.getCheckedPni(),
|
ourPni: window.textsecure.storage.user.getCheckedPni(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue