diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 496f4f457..cafa1c320 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -342,7 +342,7 @@
"leaveAndRemoveForEveryone": "Leave Group and Remove for Everyone",
"leaveGroupConfirmation": "Are you sure you want to leave $name$?",
"leaveGroupConfirmationAdmin": "As you are the admin of this group, if you leave it it will be removed for every current members. Are you sure you want to leave this group?",
- "leaveGroupConrirmationOnlyAdminLegacy": "Because you are the creator of this group it will be deleted for everyone. This cannot be undone.",
+ "leaveGroupConfirmationOnlyAdminLegacy": "Because you are the creator of this group it will be deleted for everyone. This cannot be undone.",
"leaveGroupConfirmationOnlyAdmin": "You are the only admin in $name$",
"leaveGroupConfirmationOnlyAdminWarning": "Group settings and members cannot be changed without an admin",
"leaveGroupFailed": "Failed to leave Group!",
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts
index 55ec30d0f..59cfa1c20 100644
--- a/ts/interactions/conversationInteractions.ts
+++ b/ts/interactions/conversationInteractions.ts
@@ -397,9 +397,9 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
const isClosedGroup = conversation.isClosedGroup() || false;
const isPublic = conversation.isPublic() || false;
- const admins = conversation.get('groupAdmins') || [];
+ const admins = conversation.getGroupAdmins();
const isAdmin = admins.includes(UserUtils.getOurPubKeyStrFromCache());
- const showOnlyGroupAdminWarning = isClosedGroup && isAdmin && admins.length === 1;
+ const showOnlyGroupAdminWarning = isClosedGroup && isAdmin;
const lastMessageInteractionType = conversation.get('lastMessageInteractionType');
const lastMessageInteractionStatus = conversation.get('lastMessageInteractionStatus');
@@ -432,7 +432,9 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
window?.inboxStore?.dispatch(
updateConfirmModal({
title: window.i18n('leaveGroup'),
- message: window.i18n('leaveGroupConrirmationOnlyAdminLegacy', name ? [name] : ['']),
+ message: window.i18n('leaveGroupConfirmationOnlyAdminLegacy', [
+ name || window.i18n('unknown'),
+ ]),
onClickOk,
okText: window.i18n('leave'),
okTheme: SessionButtonColor.Danger,
@@ -440,7 +442,7 @@ export async function showLeaveGroupByConvoId(conversationId: string, name: stri
conversationId,
})
);
- // TODO Only to be used after the closed group rebuild
+ // TODO AUDRIC this is chunk3 stuff: Only to be used after the closed group rebuild chunk3
// const onClickOkLastAdmin = () => {
// /* TODO */
// };
diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts
index f05c7d034..6acb8f743 100644
--- a/ts/models/conversation.ts
+++ b/ts/models/conversation.ts
@@ -1401,7 +1401,7 @@ export class ConversationModel extends Backbone.Model {
if (!pubKey) {
throw new Error('isAdmin() pubKey is falsy');
}
- const groupAdmins = getLibGroupAdminsOutsideRedux(this.id) || this.getGroupAdmins();
+ const groupAdmins = this.getGroupAdmins();
return Array.isArray(groupAdmins) && groupAdmins.includes(pubKey);
}
@@ -1956,7 +1956,7 @@ export class ConversationModel extends Backbone.Model {
}
public getGroupAdmins(): Array {
- const groupAdmins = this.get('groupAdmins');
+ const groupAdmins = getLibGroupAdminsOutsideRedux(this.id) || this.get('groupAdmins');
return groupAdmins && groupAdmins.length > 0 ? groupAdmins : [];
}
diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts
index 9c767ff0b..218951c9d 100644
--- a/ts/session/conversations/ConversationController.ts
+++ b/ts/session/conversations/ConversationController.ts
@@ -224,15 +224,14 @@ class ConvoController {
await leaveClosedGroup(groupId, fromSyncMessage);
window.log.info(`deleteClosedGroup: ${groupId}, sendLeaveMessage?:${sendLeaveMessage}`);
}
-
- // if we were kicked or sent our left message, we have nothing to do more with that group.
- // Just delete everything related to it, not trying to add update message or send a left message.
- await this.removeGroupOrCommunityFromDBAndRedux(groupId);
if (PubKey.is03Pubkey(groupId)) {
await remove03GroupFromWrappers(groupId);
} else {
await removeLegacyGroupFromWrappers(groupId);
}
+ // if we were kicked or sent our left message, we have nothing to do more with that group.
+ // Just delete everything related to it, not trying to add update message or send a left message.
+ await this.removeGroupOrCommunityFromDBAndRedux(groupId);
if (!fromSyncMessage) {
await UserSync.queueNewJobIfNeeded();
@@ -456,6 +455,7 @@ class ConvoController {
/**
* You most likely don't want to call this function directly, but instead use the deleteLegacyGroup() from the ConversationController as it will take care of more cleaningup.
+ * This throws if a leaveMessage needs to be sent, but fails to be sent.
*
* Note: `fromSyncMessage` is used to know if we need to send a leave group message to the group first.
* So if the user made the action on this device, fromSyncMessage should be false, but if it happened from a linked device polled update, set this to true.
@@ -512,20 +512,17 @@ async function leaveClosedGroup(groupPk: PubkeyType | GroupPubkeyType, fromSyncM
// We might not be able to send our leaving messages (no encryption keypair, we were already removed, no network, etc).
// If that happens, we should just remove everything from our current user.
- try {
- const wasSent = await getMessageQueue().sendToGroupV2NonDurably({
- message: ourLeavingMessage,
- });
- if (!wasSent) {
- throw new Error(
- `Even with the retries, leaving message for group ${ed25519Str(
- groupPk
- )} failed to be sent... Still deleting everything`
- );
- }
- } catch (e) {
- window.log.warn('leaving groupv2 error:', e.message);
+ const wasSent = await getMessageQueue().sendToGroupV2NonDurably({
+ message: ourLeavingMessage,
+ });
+ if (!wasSent) {
+ throw new Error(
+ `Even with the retries, leaving message for group ${ed25519Str(
+ groupPk
+ )} failed to be sent...`
+ );
}
+
// the rest of the cleaning of that conversation is done in the `deleteClosedGroup()`
return;
@@ -579,12 +576,7 @@ async function removeLegacyGroupFromWrappers(groupId: string) {
}
async function remove03GroupFromWrappers(groupPk: GroupPubkeyType) {
- getSwarmPollingInstance().removePubkey(groupPk, 'remove03GroupFromWrappers');
-
- await UserGroupsWrapperActions.eraseGroup(groupPk);
- await SessionUtilConvoInfoVolatile.removeGroupFromWrapper(groupPk);
window?.inboxStore?.dispatch(groupInfoActions.destroyGroupDetails({ groupPk }));
- window.log.info(`removed 03 from metagroup wrapper ${ed25519Str(groupPk)}`);
}
async function removeCommunityFromWrappers(conversationId: string) {
diff --git a/ts/state/ducks/metaGroups.ts b/ts/state/ducks/metaGroups.ts
index 2bf0776d2..8b8b51de5 100644
--- a/ts/state/ducks/metaGroups.ts
+++ b/ts/state/ducks/metaGroups.ts
@@ -30,6 +30,7 @@ import { ClosedGroup } from '../../session/group/closed-group';
import { GroupUpdateInfoChangeMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateInfoChangeMessage';
import { GroupUpdateMemberChangeMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_group/GroupUpdateMemberChangeMessage';
import { GroupUpdateDeleteMessage } from '../../session/messages/outgoing/controlMessage/group_v2/to_user/GroupUpdateDeleteMessage';
+import { ed25519Str } from '../../session/onions/onionPath';
import { PubKey } from '../../session/types';
import { UserUtils } from '../../session/utils';
import { PreConditionFailed } from '../../session/utils/errors';
@@ -38,6 +39,7 @@ import { GroupSync } from '../../session/utils/job_runners/jobs/GroupSyncJob';
import { UserSync } from '../../session/utils/job_runners/jobs/UserSyncJob';
import { RunJobResult } from '../../session/utils/job_runners/PersistedJob';
import { LibSessionUtil } from '../../session/utils/libsession/libsession_utils';
+import { SessionUtilConvoInfoVolatile } from '../../session/utils/libsession/libsession_utils_convo_info_volatile';
import { getUserED25519KeyPairBytes } from '../../session/utils/User';
import { stringify, toFixedUint8ArrayOfLength } from '../../types/sqlSharedTypes';
import {
@@ -382,14 +384,36 @@ const refreshGroupDetailsFromWrapper = createAsyncThunk(
const destroyGroupDetails = createAsyncThunk(
'group/destroyGroupDetails',
async ({ groupPk }: { groupPk: GroupPubkeyType }) => {
- try {
- await UserGroupsWrapperActions.eraseGroup(groupPk);
- await ConfigDumpData.deleteDumpFor(groupPk);
+ debugger;
+ const us = UserUtils.getOurPubKeyStrFromCache();
+ const weAreAdmin = await checkWeAreAdmin(groupPk);
+ const allMembers = await MetaGroupWrapperActions.memberGetAll(groupPk);
+ const otherAdminsCount = allMembers
+ .filter(m => m.admin || m.promoted)
+ .filter(m => m.pubkeyHex !== us).length;
+
+ // we are the last admin promoted
+ if (weAreAdmin && otherAdminsCount === 0) {
+ // this marks the group info as deleted. We need to push those details
await MetaGroupWrapperActions.infoDestroy(groupPk);
- getSwarmPollingInstance().removePubkey(groupPk, 'destroyGroupDetails');
- } catch (e) {
- window.log.warn(`destroyGroupDetails for ${groupPk} failed with ${e.message}`);
+ const lastPushResult = await GroupSync.pushChangesToGroupSwarmIfNeeded({
+ groupPk,
+ revokeSubRequest: null,
+ unrevokeSubRequest: null,
+ supplementKeys: [],
+ });
+ if (lastPushResult !== RunJobResult.Success) {
+ throw new Error(`Failed to destroyGroupDetails for pk ${ed25519Str(groupPk)}`);
+ }
}
+
+ // this deletes the secretKey if we had it. If we need it for something, it has to be done before this call.
+ await UserGroupsWrapperActions.eraseGroup(groupPk);
+ await SessionUtilConvoInfoVolatile.removeGroupFromWrapper(groupPk);
+ await ConfigDumpData.deleteDumpFor(groupPk);
+
+ getSwarmPollingInstance().removePubkey(groupPk, 'destroyGroupDetails');
+
return { groupPk };
}
);
@@ -1073,11 +1097,13 @@ const handleMemberLeftMessage = createAsyncThunk(
);
}
- await handleMemberRemovedFromUI({
- groupPk,
- removeMembers: [memberLeft],
- fromMemberLeftMessage: true,
- });
+ if (await checkWeAreAdmin(groupPk)) {
+ await handleMemberRemovedFromUI({
+ groupPk,
+ removeMembers: [memberLeft],
+ fromMemberLeftMessage: true,
+ });
+ }
return {
groupPk,
@@ -1303,7 +1329,7 @@ const metaGroupSlice = createSlice({
});
builder.addCase(destroyGroupDetails.fulfilled, (state, action) => {
const { groupPk } = action.payload;
- // FIXME destroyGroupDetails marks the info as destroyed, but does not really remove the wrapper currently
+ window.log.info(`removed 03 from metagroup wrapper ${ed25519Str(groupPk)}`);
deleteGroupPkEntriesFromState(state, groupPk);
});
builder.addCase(destroyGroupDetails.rejected, (_state, action) => {
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index c7bb011f4..458be881c 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -291,7 +291,7 @@ export type LocalizerKeys =
| 'leaveGroupConfirmationAdmin'
| 'leaveGroupConfirmationOnlyAdmin'
| 'leaveGroupConfirmationOnlyAdminWarning'
- | 'leaveGroupConrirmationOnlyAdminLegacy'
+ | 'leaveGroupConfirmationOnlyAdminLegacy'
| 'leaveGroupFailed'
| 'leaveGroupFailedPleaseTryAgain'
| 'leaving'