fix: add way to render group update add with history

pull/2963/head
Audric Ackermann 2 years ago
parent 153846a12b
commit 13da2b5632

@ -233,11 +233,12 @@
"disappearingMessagesModeLegacy": "Legacy",
"disappearingMessagesModeLegacySubtitle": "Original version of disappearing messages.",
"disappearingMessagesDisabled": "Disappearing messages disabled",
"disabledDisappearingMessages": "<b>$name$</b> has turned <b>off</b> disappearing messages.",
"youDisabledDisappearingMessages": "<b>You</b> have turned <b>off</b> disappearing messages.",
"youDisabledYourDisappearingMessages": "<b>You</b> turned <b>off</b> disappearing messages. Messages you send will no longer disappear.",
"groupDisabledDisappearingMessages": "<b>$name$</b> has turned disappearing messages <b>off</b>.",
"updateDisappearingMessagesFallback": "<b>$name$</b> updated disappearing message settings.",
"youDisabledDisappearingMessages": "<b>You</b> have turned disappearing messages <b>off</b>.",
"youDisabledYourDisappearingMessages": "<b>You</b> turned disappearing messages <b>off</b>. Messages you send will no longer disappear.",
"youSetYourDisappearingMessages": "<b>You</b> set your messages to disappear <b>$time$</b> after they have been <b>$type$</b>.",
"theyDisabledTheirDisappearingMessages": "<b>$name$</b> has turned <b>off</b> disappearing messages. Messages they send will no longer disappear.",
"theyDisabledTheirDisappearingMessages": "<b>$name$</b> has turned disappearing messages <b>off</b>. Messages they send will no longer disappear.",
"theySetTheirDisappearingMessages": "<b>$name$</b> has set their messages to disappear <b>$time$</b> after they have been <b>$type$</b>.",
"timerSetTo": "Disappearing message time set to $time$",
"set": "Set",
@ -271,10 +272,15 @@
"groupNameChangeFallback": "Group name updated.",
"groupAvatarChange": "Group display picture updated.",
"groupOneJoined": "<b>$name$</b> joined the group.",
"groupYouJoined": "<b>You</b> joined the group.",
"groupTwoJoined": "<b>$first$</b> and <b>$second$</b> joined the group.",
"groupOthersJoined": "<b>$name$</b> and <b>$count$ others</b> joined the group.",
"groupOneJoined": "<b>$name$</b> was invited to join the group.",
"groupYouJoined": "<b>You</b> were invited to join the group.",
"groupTwoJoined": "<b>$first$</b> and <b>$second$</b> were invited to join the group.",
"groupOthersJoined": "<b>$name$</b> and <b>$count$ others</b> were invited to join the group.",
"groupOneJoinedWithHistory": "<b>$name$</b> was invited to join the group. Chat history was shared.",
"groupYouJoinedWithHistory": "<b>You</b> were invited to join the group. Chat history was shared.",
"groupTwoJoinedWithHistory": "<b>$first$</b> and <b>$second$</b> were invited to join the group. Chat history was shared.",
"groupOthersJoinedWithHistory": "<b>$name$</b> and <b>$count$ others</b> were invited to join the group. Chat history was shared.",
"groupOneRemoved": "<b>$name$</b> was removed from the group.",
"groupYouRemoved": "<b>You</b> were removed from the group.",

@ -112,7 +112,9 @@ message GroupUpdateMemberChangeMessage {
required Type type = 1;
repeated string memberSessionIds = 2;
required bytes adminSignature = 3;
optional bool historyShared = 3;
required bytes adminSignature = 4;
}

@ -150,7 +150,9 @@ function useTextToRender(props: PropsForExpirationTimer) {
case 'fromOther':
return disabled
? window.i18n(
ownSideOnly ? 'theyDisabledTheirDisappearingMessages' : 'disabledDisappearingMessages',
ownSideOnly
? 'theyDisabledTheirDisappearingMessages'
: 'groupDisabledDisappearingMessages',
[contact, timespanText]
)
: mode

@ -57,7 +57,7 @@ function changeOfMembersV2({
type,
us,
}: {
type: 'added' | 'promoted' | 'removed';
type: 'added' | 'addedWithHistory' | 'promoted' | 'removed';
changedWithNames: Array<IdWithName>;
us: PubkeyType;
}): string {
@ -75,7 +75,13 @@ function changeOfMembersV2({
: 'Others';
const action =
type === 'added' ? 'Joined' : type === 'promoted' ? 'Promoted' : ('Removed' as const);
type === 'addedWithHistory'
? 'JoinedWithHistory'
: type === 'added'
? 'Joined'
: type === 'promoted'
? 'Promoted'
: ('Removed' as const);
const key = `group${subject}${action}` as const;
return window.i18n(
@ -85,7 +91,7 @@ function changeOfMembersV2({
}
// TODO those lookups might need to be memoized
const ChangeItemJoined = (added: Array<PubkeyType>): string => {
const ChangeItemJoined = (added: Array<PubkeyType>, withHistory: boolean): string => {
if (!added.length) {
throw new Error('Group update add is missing contacts');
}
@ -95,7 +101,7 @@ const ChangeItemJoined = (added: Array<PubkeyType>): string => {
if (isGroupV2) {
return changeOfMembersV2({
changedWithNames: mapIdsWithNames(added, names),
type: 'added',
type: withHistory ? 'addedWithHistory' : 'added',
us,
});
}
@ -182,7 +188,7 @@ const ChangeItem = (change: PropsForGroupUpdateType): string => {
case 'name':
return ChangeItemName(change.newName);
case 'add':
return ChangeItemJoined(change.added);
return ChangeItemJoined(change.added, change.withHistory);
case 'left':
return ChangeItemLeft(change.left);
case 'kicked':

@ -455,6 +455,15 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
const change: PropsForGroupUpdateAdd = {
type: 'add',
added: groupUpdate.joined as Array<PubkeyType>,
withHistory: false,
};
return { change, ...sharedProps };
}
if (groupUpdate.joinedWithHistory?.length) {
const change: PropsForGroupUpdateAdd = {
type: 'add',
added: groupUpdate.joined as Array<PubkeyType>,
withHistory: true,
};
return { change, ...sharedProps };
}
@ -522,7 +531,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return undefined;
}
const readBy = this.get('read_by') || [];
if (Storage.get(SettingsKey.settingsReadReceipt) && readBy.length > 0) {
return 'read';

@ -156,6 +156,7 @@ export type PropsForMessageRequestResponse = MessageRequestResponseMsg & {
export type MessageGroupUpdate = {
left?: Array<string>;
joined?: Array<string>;
joinedWithHistory?: Array<string>;
kicked?: Array<string>;
promoted?: Array<PubkeyType>;
name?: string;

@ -689,6 +689,7 @@ async function handleClosedGroupMembersAdded(
const groupDiff: GroupDiff = {
type: 'add',
added: membersNotAlreadyPresent,
withHistory: false,
};
await ClosedGroup.addUpdateMessage({
convo,

@ -285,7 +285,7 @@ async function handleGroupMemberChangeMessage({
switch (change.type) {
case SignalService.GroupUpdateMemberChangeMessage.Type.ADDED: {
await ClosedGroup.addUpdateMessage({
diff: { type: 'add', added: filteredMemberChange },
diff: { type: 'add', added: filteredMemberChange, withHistory: change.historyShared },
...sharedDetails,
});

@ -89,11 +89,11 @@ async function initiateClosedGroupUpdate(
expireTimer,
};
const diff = buildGroupDiff(convo, groupDetails);
const diff = buildGroupV1Diff(convo, groupDetails);
await updateOrCreateClosedGroup(groupDetails);
if (!diff) {
window.log.warn('buildGroupDiff returned null');
window.log.warn('buildGroupV1Diff returned null');
await convo.commit();
return;
@ -126,7 +126,7 @@ async function initiateClosedGroupUpdate(
}
if (diff.type === 'add' && diff.added?.length) {
const joiningOnlyDiff: GroupDiff = _.pick(diff, ['type', 'added']);
const joiningOnlyDiff: GroupDiff = _.pick(diff, ['type', 'added', 'withHistory']);
const dbMessageAdded = await addUpdateMessage({
diff: joiningOnlyDiff,
@ -213,7 +213,7 @@ export async function addUpdateMessage({
});
}
function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff | null {
function buildGroupV1Diff(convo: ConversationModel, update: GroupInfo): GroupDiff | null {
if (convo.getRealSessionUsername() !== update.name) {
return { type: 'name', newName: update.name };
}
@ -228,7 +228,7 @@ function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff
PubKey.is05Pubkey
);
if (added.length > 0) {
return { type: 'add', added };
return { type: 'add', added, withHistory: false };
}
// Check if anyone got kicked:
const removedMembers = _.difference(oldMembersWithZombies, newMembersWithZombiesLeft).filter(

@ -12,17 +12,22 @@ import {
} from '../GroupUpdateMessage';
type MembersAddedMessageParams = GroupUpdateMessageParams & {
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.ADDED;
typeOfChange: 'added';
added: Array<PubkeyType>;
};
type MembersAddedWithHistoryMessageParams = GroupUpdateMessageParams & {
typeOfChange: 'addedWithHistory';
added: Array<PubkeyType>;
};
type MembersRemovedMessageParams = GroupUpdateMessageParams & {
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.REMOVED;
typeOfChange: 'removed';
removed: Array<PubkeyType>;
};
type MembersPromotedMessageParams = GroupUpdateMessageParams & {
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.PROMOTED;
typeOfChange: 'promoted';
promoted: Array<PubkeyType>;
};
@ -30,7 +35,8 @@ type MembersPromotedMessageParams = GroupUpdateMessageParams & {
* GroupUpdateInfoChangeMessage is sent to the group's swarm.
*/
export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage {
public readonly typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type;
public readonly typeOfChange: 'added' | 'addedWithHistory' | 'removed' | 'promoted';
public readonly memberSessionIds: Array<PubkeyType> = []; // added, removed, promoted based on the type.
public readonly namespace = SnodeNamespaces.ClosedGroupMessages;
private readonly secretKey: Uint8Array; // not sent, only used for signing content as part of the message
@ -41,11 +47,11 @@ export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage {
| MembersAddedMessageParams
| MembersRemovedMessageParams
| MembersPromotedMessageParams
| MembersAddedWithHistoryMessageParams
) &
AdminSigDetails
) {
super(params);
const { Type } = SignalService.GroupUpdateMemberChangeMessage;
const { typeOfChange } = params;
this.typeOfChange = typeOfChange;
@ -53,21 +59,28 @@ export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage {
this.sodium = params.sodium;
switch (typeOfChange) {
case Type.ADDED: {
case 'added': {
if (isEmpty(params.added)) {
throw new Error('added members list cannot be empty');
}
this.memberSessionIds = params.added;
break;
}
case Type.REMOVED: {
case 'addedWithHistory': {
if (isEmpty(params.added)) {
throw new Error('addedWithHistory members list cannot be empty');
}
this.memberSessionIds = params.added;
break;
}
case 'removed': {
if (isEmpty(params.removed)) {
throw new Error('removed members list cannot be empty');
}
this.memberSessionIds = params.removed;
break;
}
case Type.PROMOTED: {
case 'promoted': {
if (isEmpty(params.promoted)) {
throw new Error('promoted members list cannot be empty');
}
@ -80,8 +93,15 @@ export class GroupUpdateMemberChangeMessage extends GroupUpdateMessage {
}
public dataProto(): SignalService.DataMessage {
const { Type } = SignalService.GroupUpdateMemberChangeMessage;
const memberChangeMessage = new SignalService.GroupUpdateMemberChangeMessage({
type: this.typeOfChange,
type:
this.typeOfChange === 'added' || this.typeOfChange === 'addedWithHistory'
? Type.ADDED
: this.typeOfChange === 'removed'
? Type.REMOVED
: Type.PROMOTED,
memberSessionIds: this.memberSessionIds,
adminSignature: this.sodium.crypto_sign_detached(
stringToUint8Array(`MEMBER_CHANGE${this.typeOfChange}${this.createAtNetworkTimestamp}`),

@ -104,6 +104,7 @@ export type PropsForExpirationTimer = {
export type PropsForGroupUpdateAdd = {
type: 'add';
withHistory: boolean;
added: Array<PubkeyType>;
};

@ -608,8 +608,10 @@ async function getUpdateMessagesToPush({
removed,
adminSecretKey,
createAtNetworkTimestamp,
fromMemberLeftMessage,
}: WithAddWithHistoryMembers &
WithAddWithoutHistoryMembers &
WithFromMemberLeftMessage &
WithRemoveMembers &
WithFromCurrentDevice &
WithGroupPubkey & {
@ -621,17 +623,29 @@ async function getUpdateMessagesToPush({
const updateMessages: Array<GroupUpdateMemberChangeMessage> = [];
if (!fromCurrentDevice) {
if (!fromCurrentDevice || fromMemberLeftMessage) {
return updateMessages;
}
const allAdded = [...withHistory, ...withoutHistory]; // those are already enforced to be unique (and without intersection) in `validateMemberChange()`
if (allAdded.length) {
if (withoutHistory.length) {
updateMessages.push(
new GroupUpdateMemberChangeMessage({
added: withoutHistory,
groupPk,
typeOfChange: 'added',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
...getConvoExpireDetailsForMsg(convo),
})
);
}
if (withHistory.length) {
updateMessages.push(
new GroupUpdateMemberChangeMessage({
added: allAdded,
added: withHistory,
groupPk,
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.ADDED,
typeOfChange: 'addedWithHistory',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
@ -644,7 +658,7 @@ async function getUpdateMessagesToPush({
new GroupUpdateMemberChangeMessage({
removed,
groupPk,
typeOfChange: SignalService.GroupUpdateMemberChangeMessage.Type.REMOVED,
typeOfChange: 'removed',
createAtNetworkTimestamp,
secretKey: adminSecretKey,
sodium,
@ -652,6 +666,7 @@ async function getUpdateMessagesToPush({
})
);
}
// TODO might need to add the promote case here
return updateMessages;
}
@ -704,6 +719,7 @@ async function handleMemberAddedFromUIOrNot({
withHistory,
withoutHistory,
createAtNetworkTimestamp,
fromMemberLeftMessage: false,
});
await LibSessionUtil.saveDumpsToDb(groupPk);
@ -744,23 +760,21 @@ async function handleMemberAddedFromUIOrNot({
: null,
},
};
const additions = updateMessages.find(
m => m.typeOfChange === SignalService.GroupUpdateMemberChangeMessage.Type.ADDED
);
if (additions) {
const additionsWithoutHistory = updateMessages.find(m => m.typeOfChange === 'added');
const additionsWithHistory = updateMessages.find(m => m.typeOfChange === 'addedWithHistory');
if (additionsWithoutHistory) {
await ClosedGroup.addUpdateMessage({
diff: { type: 'add', added: additions.memberSessionIds },
diff: { type: 'add', added: additionsWithoutHistory.memberSessionIds, withHistory: false },
...shared,
expireUpdate: {
expirationTimer: expiringDetails.expireTimer,
expirationType: expiringDetails.expirationType,
messageExpirationFromRetrieve:
expiringDetails.expireTimer > 0
? createAtNetworkTimestamp + expiringDetails.expireTimer
: null,
},
});
}
if (additionsWithHistory) {
await ClosedGroup.addUpdateMessage({
diff: { type: 'add', added: additionsWithHistory.memberSessionIds, withHistory: true },
...shared,
});
}
await convo.commit();
}
@ -819,6 +833,7 @@ async function handleMemberRemovedFromUIOrNot({
withHistory: [],
withoutHistory: [],
createAtNetworkTimestamp,
fromMemberLeftMessage,
});
await LibSessionUtil.saveDumpsToDb(groupPk);
@ -858,9 +873,7 @@ async function handleMemberRemovedFromUIOrNot({
},
};
const removals = updateMessages.find(
m => m.typeOfChange === SignalService.GroupUpdateMemberChangeMessage.Type.REMOVED
);
const removals = updateMessages.find(m => m.typeOfChange === 'removed');
if (removals) {
await ClosedGroup.addUpdateMessage({

@ -87,12 +87,7 @@ export function getSelectedCanWrite(state: StateType) {
const isBlindedAndDisabledMsgRequests = getSelectedBlindedDisabledMsgRequests(state); // true if isPrivate, blinded and explicitely disabled msgreq
return !(
isBlocked ||
isKickedFromGroup ||
readOnlySogs ||
isBlindedAndDisabledMsgRequests
);
return !(isBlocked || isKickedFromGroup || readOnlySogs || isBlindedAndDisabledMsgRequests);
}
function getSelectedBlindedDisabledMsgRequests(state: StateType) {

@ -142,7 +142,6 @@ export type LocalizerKeys =
| 'dialogClearAllDataDeletionFailedTitle'
| 'dialogClearAllDataDeletionFailedTitleQuestion'
| 'dialogClearAllDataDeletionQuestion'
| 'disabledDisappearingMessages'
| 'disappearingMessages'
| 'disappearingMessagesDisabled'
| 'disappearingMessagesModeAfterRead'
@ -206,6 +205,7 @@ export type LocalizerKeys =
| 'goToReleaseNotes'
| 'goToSupportPage'
| 'groupAvatarChange'
| 'groupDisabledDisappearingMessages'
| 'groupInviteFailedOne'
| 'groupInviteFailedOthers'
| 'groupInviteFailedTwo'
@ -214,16 +214,20 @@ export type LocalizerKeys =
| 'groupNameChangeFallback'
| 'groupNamePlaceholder'
| 'groupOneJoined'
| 'groupOneJoinedWithHistory'
| 'groupOneLeft'
| 'groupOnePromoted'
| 'groupOneRemoved'
| 'groupOthersJoined'
| 'groupOthersJoinedWithHistory'
| 'groupOthersPromoted'
| 'groupOthersRemoved'
| 'groupTwoJoined'
| 'groupTwoJoinedWithHistory'
| 'groupTwoPromoted'
| 'groupTwoRemoved'
| 'groupYouJoined'
| 'groupYouJoinedWithHistory'
| 'groupYouLeft'
| 'groupYouPromoted'
| 'groupYouRemoved'
@ -534,6 +538,7 @@ export type LocalizerKeys =
| 'unknownCountry'
| 'unpinConversation'
| 'unreadMessages'
| 'updateDisappearingMessagesFallback'
| 'updateGroupDialogTitle'
| 'userAddedToModerators'
| 'userBanFailed'
@ -563,8 +568,8 @@ export type LocalizerKeys =
| 'youGotKickedFromGroup'
| 'youHaveANewFriendRequest'
| 'youLeftTheGroup'
| 'youWereInvitedToGroup'
| 'youSetYourDisappearingMessages'
| 'youWereInvitedToGroup'
| 'yourSessionID'
| 'yourUniqueSessionID'
| 'zoomFactorSettingTitle';

Loading…
Cancel
Save