diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 6b830b49b..8a925c841 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -148,6 +148,7 @@ "callsNotificationsRequired": "Voice and Video Calls require notifications to be enabled in your device system settings.", "callsPermissionsRequired": "Call Permissions Required", "callsPermissionsRequiredDescription": "You can enable the \"Voice and Video Calls\" permission in Privacy Settings.", + "callsPermissionsRequiredDescription1": "You can enable the \"Voice and Video Calls\" permission in Permissions Settings.", "callsReconnecting": "Reconnecting…", "callsRinging": "Ringing...", "callsSessionCall": "{app_name} Call", @@ -379,6 +380,7 @@ "groupCreateErrorNoMembers": "Please pick at least one other group member.", "groupDelete": "Delete Group", "groupDeleteDescription": "Are you sure you want to delete {group_name}? This will remove all members and delete all group content.", + "groupDeletedMemberDescription": "{group_name} has been deleted by a group admin. You will not be able to send any more messages.", "groupDescriptionEnter": "Enter a group description", "groupDisplayPictureUpdated": "Group display picture updated.", "groupEdit": "Edit Group", diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index 9c9b4c745..52b9a5150 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -279,6 +279,7 @@ "deleteMessageDevicesAll": "حذف از تمام دستگاه‌هایم", "deleteMessageEveryone": "حذف برای همه", "deleteMessageFailed": "{count, plural, one [خطا در حذف پیام] other [خطا در حذف پیام ها]}", + "deleteMessageWarning": "{count, plural, one [این پیام قابل حذف برای همه نیست] other [برخی از پیام هایی که انتخاب کرده اید را نمیتوان برای همه حذف کرد]}", "deleteMessagesDescriptionEveryone": "آیا مطمئن هستید می‌خواهید این پیام‌ها را برای همه حذف کنید؟", "deleting": "در حال حذف", "developerToolsToggle": "تاگل ابزار های توسعه دهنده", @@ -382,6 +383,7 @@ "groupInviteFailedMultiple": "دعوت از {name} و {count} نفر دیگر به {group_name} انجام نشد", "groupInviteFailedTwo": "دعوت از {name} و {other_name} به {group_name} انجام نشد", "groupInviteFailedUser": "دعوت از {name} به {group_name} انجام نشد", + "groupInviteSending": "{count, plural, one [ارسال دعوت نامه] other [ارسال دعوت نامه ها]}", "groupInviteSent": "دعوت نامه ارسال شد", "groupInviteSuccessful": "دعوت به گروه موفقیت‌آمیز بود", "groupInviteVersion": "کاربران باید آخرین نسخه را داشته باشند تا دعوت‌نامه دریافت کنند", diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index 3fad75ef7..67928b2d1 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -35,6 +35,7 @@ "adminRemovedUser": "{name} is verwijderd als Admin.", "adminRemovedUserMultiple": "{name} en {count} anderen zijn verwijderd als beheerder.", "adminRemovedUserOther": "{name} en {other_name} zijn verwijderd als beheerder.", + "adminSendingPromotion": "{count, plural, one [Beheerder promotie versturen] other [Beheerder promoties versturen]}", "adminSettings": "Admin instellingen", "adminTwoPromotedToAdmin": "{name} en {other_name} zijn gepromoveerd tot Admin.", "andMore": "+{count}", @@ -274,9 +275,11 @@ "deleteAfterLegacyGroupsGroupUpdateErrorTitle": "Het is mislukt om de groep bij te werken", "deleteAfterMessageDeletionStandardisationMessageDeletionForbidden": "Je hebt geen toestemming om andermans berichten te verwijderen", "deleteMessage": "{count, plural, one [Verwijder bericht] other [Verwijder berichten]}", + "deleteMessageConfirm": "{count, plural, one [Weet u zeker dat u dit bericht wilt verwijderen?] other [Weet u zeker dat u deze berichten wilt verwijderen?]}", "deleteMessageDeleted": "{count, plural, one [Bericht verwijderd] other [Berichten verwijderd]}", "deleteMessageDeletedGlobally": "Dit bericht is verwijderd", "deleteMessageDeletedLocally": "Dit bericht is op dit apparaat verwijderd", + "deleteMessageDescriptionDevice": "{count, plural, one [Weet u zeker dat u dit bericht enkel van dit apparaat wilt verwijderen?] other [Weet u zeker dat u deze berichten enkel van dit apparaat wilt verwijderen?]}", "deleteMessageDescriptionEveryone": "Weet u zeker dat u dit bericht voor iedereen wilt verwijderen?", "deleteMessageDeviceOnly": "Alleen verwijderen op dit apparaat", "deleteMessageDevicesAll": "Verwijder op al mijn apparaten", @@ -385,6 +388,7 @@ "groupInviteFailedMultiple": "Het uitnodigen van {name} en {count} anderen naar {group_name} is mislukt", "groupInviteFailedTwo": "Het uitnodigen van {name} en {other_name} naar {group_name} is mislukt", "groupInviteFailedUser": "Het uitnodigen van {name} naar {group_name} is mislukt", + "groupInviteSending": "{count, plural, one [Uitnodiging versturen] other [Uitnodigingen versturen]}", "groupInviteSent": "Uitnodiging verzonden", "groupInviteSuccessful": "Groepsuitnodiging succesvol", "groupInviteVersion": "Gebruikers moeten de nieuwste versie hebben om uitnodigingen te ontvangen", diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 4b44f9e6a..d1d61fd05 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -274,9 +274,11 @@ "deleteAfterLegacyGroupsGroupUpdateErrorTitle": "Ошибка при обновлении группы", "deleteAfterMessageDeletionStandardisationMessageDeletionForbidden": "У вас недостаточно прав для удаления других сообщений", "deleteMessage": "{count, plural, one [Удалить Сообщение] few [Удалить сообщения] many [Удалить сообщения] other [Удалить сообщения]}", + "deleteMessageConfirm": "{count, plural, one [Вы уверены, что хотите удалить это сообщение?] few [Вы уверены, что хотите удалить эти сообщения?] many [Вы уверены, что хотите удалить эти сообщения?] other [Вы уверены, что хотите удалить эти сообщения?]}", "deleteMessageDeleted": "{count, plural, one [Сообщение удалено] few [Сообщения удалены] many [Сообщения удалены] other [Сообщения удалены]}", "deleteMessageDeletedGlobally": "Это сообщение было удалено", "deleteMessageDeletedLocally": "Это сообщение было удалено на этом устройстве", + "deleteMessageDescriptionDevice": "{count, plural, one [Вы уверены, что хотите удалить это сообщение только с этого устройства?] few [Вы уверены, что хотите удалить эти сообщения только с этого устройства?] many [Вы уверены, что хотите удалить эти сообщения только с этого устройства?] other [Вы уверены, что хотите удалить эти сообщения только с этого устройства?]}", "deleteMessageDescriptionEveryone": "Вы уверены, что хотите удалить это сообщение для всех?", "deleteMessageDeviceOnly": "Удалить только на этом устройстве", "deleteMessageDevicesAll": "Удалить на всех моих устройствах", @@ -385,6 +387,7 @@ "groupInviteFailedMultiple": "Не удалось пригласить {name} и {count} других в {group_name}", "groupInviteFailedTwo": "Не удалось пригласить {name} и {other_name} в {group_name}", "groupInviteFailedUser": "Не удалось пригласить {name} в {group_name}", + "groupInviteSending": "{count, plural, one [Отправка приглашения] few [Отправка приглашений] many [Отправка приглашений] other [Отправка приглашений]}", "groupInviteSent": "Приглашение отправлено", "groupInviteSuccessful": "Приглашение в группу успешно", "groupInviteVersion": "Пользователи должны иметь последнюю версию приложения для получения приглашений", diff --git a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx index 04cefd52f..efbfb4ef9 100644 --- a/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx +++ b/ts/components/conversation/right-panel/overlay/OverlayRightPanelSettings.tsx @@ -220,7 +220,7 @@ const DestroyGroupForAllMembersButton = () => { onClickOk: () => { void ConvoHub.use().deleteGroup(groupPk, { deleteAllMessagesOnSwarm: true, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', fromSyncMessage: false, sendLeaveMessage: false, forceDestroyForAllMembers: true, diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 0a427c7bd..e4f4d42d5 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -223,7 +223,7 @@ export async function declineConversationWithoutConfirm({ // when deleting a 03 group message request, we also need to remove the conversation altogether await ConvoHub.use().deleteGroup(conversationId, { deleteAllMessagesOnSwarm: false, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', forceDestroyForAllMembers: false, fromSyncMessage: false, sendLeaveMessage: false, @@ -418,7 +418,7 @@ async function leaveGroupOrCommunityByConvoId({ fromSyncMessage: false, sendLeaveMessage, deleteAllMessagesOnSwarm: false, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', forceDestroyForAllMembers: false, }); } diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts index 7edc62ad0..e89ff7a94 100644 --- a/ts/receiver/configMessage.ts +++ b/ts/receiver/configMessage.ts @@ -756,7 +756,7 @@ async function handleSingleGroupUpdateToLeave(toLeave: GroupPubkeyType) { await ConvoHub.use().deleteGroup(toLeave, { fromSyncMessage: true, sendLeaveMessage: false, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', deleteAllMessagesOnSwarm: false, forceDestroyForAllMembers: false, }); diff --git a/ts/receiver/groupv2/handleGroupV2Message.ts b/ts/receiver/groupv2/handleGroupV2Message.ts index 90b79ae4f..47a4868c4 100644 --- a/ts/receiver/groupv2/handleGroupV2Message.ts +++ b/ts/receiver/groupv2/handleGroupV2Message.ts @@ -76,6 +76,7 @@ async function getInitializedGroupObject({ secretKey: null, kicked: false, invitePending: true, + destroyed: false, }; } diff --git a/ts/receiver/libsession/handleLibSessionMessage.ts b/ts/receiver/libsession/handleLibSessionMessage.ts index ba537e8a3..e7975c5f3 100644 --- a/ts/receiver/libsession/handleLibSessionMessage.ts +++ b/ts/receiver/libsession/handleLibSessionMessage.ts @@ -54,7 +54,7 @@ async function handleLibSessionKickedMessage({ await ConvoHub.use().deleteGroup(groupPk, { sendLeaveMessage: false, fromSyncMessage: false, - emptyGroupButKeepAsKicked: !inviteWasPending, + deletionType: inviteWasPending ? 'doNotKeep' : 'keepAsKicked', deleteAllMessagesOnSwarm: false, forceDestroyForAllMembers: false, }); diff --git a/ts/session/apis/snode_api/swarmPolling.ts b/ts/session/apis/snode_api/swarmPolling.ts index 47a022221..74be4a403 100644 --- a/ts/session/apis/snode_api/swarmPolling.ts +++ b/ts/session/apis/snode_api/swarmPolling.ts @@ -681,7 +681,7 @@ export class SwarmPolling { await ConvoHub.use().deleteGroup(pubkey, { fromSyncMessage: true, sendLeaveMessage: false, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', deleteAllMessagesOnSwarm: false, forceDestroyForAllMembers: false, }); diff --git a/ts/session/apis/snode_api/swarm_polling_config/SwarmPollingGroupConfig.ts b/ts/session/apis/snode_api/swarm_polling_config/SwarmPollingGroupConfig.ts index 94995ee54..b102826f2 100644 --- a/ts/session/apis/snode_api/swarm_polling_config/SwarmPollingGroupConfig.ts +++ b/ts/session/apis/snode_api/swarm_polling_config/SwarmPollingGroupConfig.ts @@ -44,7 +44,7 @@ async function handleMetaMergeResults(groupPk: GroupPubkeyType) { await ConvoHub.use().deleteGroup(groupPk, { sendLeaveMessage: false, fromSyncMessage: false, - emptyGroupButKeepAsKicked: true, // we just got something from the group's swarm, so it is not pendingInvite + deletionType: 'keepAsDestroyed', // we just got something from the group's swarm, so it is not pendingInvite deleteAllMessagesOnSwarm: false, forceDestroyForAllMembers: false, }); diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts index 83c5bdfc0..4a5a312d7 100644 --- a/ts/session/conversations/ConversationController.ts +++ b/ts/session/conversations/ConversationController.ts @@ -253,12 +253,12 @@ class ConvoController { { sendLeaveMessage, fromSyncMessage, - emptyGroupButKeepAsKicked, + deletionType, deleteAllMessagesOnSwarm, forceDestroyForAllMembers, }: DeleteOptions & { sendLeaveMessage: boolean; - emptyGroupButKeepAsKicked: boolean; + deletionType: 'doNotKeep' | 'keepAsKicked' | 'keepAsDestroyed'; deleteAllMessagesOnSwarm: boolean; forceDestroyForAllMembers: boolean; } @@ -268,7 +268,7 @@ class ConvoController { } window.log.info( - `deleteGroup: ${ed25519Str(groupPk)}, sendLeaveMessage:${sendLeaveMessage}, fromSyncMessage:${fromSyncMessage}, emptyGroupButKeepAsKicked:${emptyGroupButKeepAsKicked}, deleteAllMessagesOnSwarm:${deleteAllMessagesOnSwarm}, forceDestroyForAllMembers:${forceDestroyForAllMembers}` + `deleteGroup: ${ed25519Str(groupPk)}, sendLeaveMessage:${sendLeaveMessage}, fromSyncMessage:${fromSyncMessage}, deletionType:${deletionType}, deleteAllMessagesOnSwarm:${deleteAllMessagesOnSwarm}, forceDestroyForAllMembers:${forceDestroyForAllMembers}` ); // this deletes all messages in the conversation @@ -294,13 +294,13 @@ class ConvoController { // when it was pendingInvite, we delete it fully, // when it was not, we empty the group but keep it with the "you have been kicked" message // Note: the pendingInvite=true case cannot really happen as we wouldn't be polling from that group (and so, not get the message kicking us) - if (emptyGroupButKeepAsKicked) { + if (deletionType === 'keepAsKicked' || deletionType === 'keepAsDestroyed') { // delete the secretKey/authData if we had it. If we need it for something, it has to be done before this call. if (groupInUserGroup) { groupInUserGroup.authData = null; groupInUserGroup.secretKey = null; groupInUserGroup.disappearingTimerSeconds = undefined; - groupInUserGroup.kicked = true; + // we want to update the groupName in user group with whatever is in the groupInfo, // so even if the group is not polled anymore, we have an up to date name on restore. let nameInMetaGroup: string | undefined; @@ -316,6 +316,11 @@ class ConvoController { groupInUserGroup.name = nameInMetaGroup; } await UserGroupsWrapperActions.setGroup(groupInUserGroup); + if (deletionType === 'keepAsKicked') { + await UserGroupsWrapperActions.setGroupKicked(groupPk); + } else { + await UserGroupsWrapperActions.setGroupDestroyed(groupPk); + } } } else { try { diff --git a/ts/state/ducks/metaGroups.ts b/ts/state/ducks/metaGroups.ts index f0ec70013..ef57e4a31 100644 --- a/ts/state/ducks/metaGroups.ts +++ b/ts/state/ducks/metaGroups.ts @@ -264,7 +264,7 @@ const initNewGroupInWrapper = createAsyncThunk( await ConvoHub.use().deleteGroup(groupPk, { fromSyncMessage: false, sendLeaveMessage: false, - emptyGroupButKeepAsKicked: false, + deletionType: 'doNotKeep', deleteAllMessagesOnSwarm: false, forceDestroyForAllMembers: false, }); diff --git a/ts/test/session/unit/crypto/SnodeSignatures_test.ts b/ts/test/session/unit/crypto/SnodeSignatures_test.ts index c28ff1902..469dda2c9 100644 --- a/ts/test/session/unit/crypto/SnodeSignatures_test.ts +++ b/ts/test/session/unit/crypto/SnodeSignatures_test.ts @@ -43,6 +43,7 @@ function getEmptyUserGroup() { name: '1243', priority: 0, pubkeyHex: validGroupPk, + destroyed: false, } as UserGroupsGet; } diff --git a/ts/webworker/workers/browser/libsession_worker_interface.ts b/ts/webworker/workers/browser/libsession_worker_interface.ts index 07c62a299..97ae9412e 100644 --- a/ts/webworker/workers/browser/libsession_worker_interface.ts +++ b/ts/webworker/workers/browser/libsession_worker_interface.ts @@ -62,7 +62,7 @@ type GenericWrapperActionsCalls = { ed25519Key: Uint8Array, dump: Uint8Array | null ) => Promise; - free: ( wrapperId: ConfigWrapperUser ) => Promise; + free: (wrapperId: ConfigWrapperUser) => Promise; confirmPushed: GenericWrapperActionsCall; dump: GenericWrapperActionsCall; makeDump: GenericWrapperActionsCall; @@ -83,7 +83,6 @@ export const GenericWrapperActions: GenericWrapperActionsCalls = { GenericWrapperActionsCalls['init'] >, - /** This function is used to free wrappers from memory only. * * See freeUserWrapper() in libsession.worker.ts */ @@ -346,6 +345,28 @@ export const UserGroupsWrapperActions: UserGroupsWrapperActionsCalls & { return cloneDeep(group); }, + setGroupKicked: async (pubkeyHex: GroupPubkeyType) => { + const group = (await callLibSessionWorker([ + 'UserGroupsConfig', + 'setGroupKicked', + pubkeyHex, + ])) as Awaited>; + groups.set(group.pubkeyHex, group); + dispatchCachedGroupsToRedux(); + return cloneDeep(group); + }, + + setGroupDestroyed: async (pubkeyHex: GroupPubkeyType) => { + const group = (await callLibSessionWorker([ + 'UserGroupsConfig', + 'setGroupDestroyed', + pubkeyHex, + ])) as Awaited>; + groups.set(group.pubkeyHex, group); + dispatchCachedGroupsToRedux(); + return cloneDeep(group); + }, + eraseGroup: async (pubkeyHex: GroupPubkeyType) => { const ret = (await callLibSessionWorker([ 'UserGroupsConfig',