diff --git a/ts/components/MemberListItem.tsx b/ts/components/MemberListItem.tsx index 38bcf782e..bf164ced8 100644 --- a/ts/components/MemberListItem.tsx +++ b/ts/components/MemberListItem.tsx @@ -224,7 +224,11 @@ const ResendInviteButton = ({ buttonType={SessionButtonType.Solid} text={window.i18n('resend')} onClick={() => { - void GroupInvite.addJob({ groupPk, member: pubkey }); + void GroupInvite.addJob({ + groupPk, + member: pubkey, + inviteAsAdmin: window.sessionFeatureFlags.useGroupV2InviteAsAdmin, + }); }} /> ); diff --git a/ts/components/dialog/UpdateGroupMembersDialog.tsx b/ts/components/dialog/UpdateGroupMembersDialog.tsx index bfa9eab96..3affeadcd 100644 --- a/ts/components/dialog/UpdateGroupMembersDialog.tsx +++ b/ts/components/dialog/UpdateGroupMembersDialog.tsx @@ -206,7 +206,7 @@ export const UpdateGroupMembersDialog = (props: Props) => { } if (groupAdmins?.includes(member)) { if (PubKey.is03Pubkey(conversationId)) { - window?.log?.warn(`User ${member} cannot be removed as they are adn admin.`); + window?.log?.warn(`User ${member} cannot be removed as they are an admin.`); return; } ToastUtils.pushCannotRemoveCreatorFromGroup(); diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 2b069fc71..6107ee36a 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -1,4 +1,4 @@ -import { isEmpty, isNil } from 'lodash'; +import { isNil } from 'lodash'; import { ConversationNotificationSettingType, READ_MESSAGE_STATE, @@ -47,16 +47,12 @@ import { urlToBlob } from '../types/attachments/VisualAttachment'; import { encryptProfile } from '../util/crypto/profileEncrypter'; import { ReleasedFeatures } from '../util/releaseFeature'; import { Storage, setLastProfileUpdateTimestamp } from '../util/storage'; -import { - MetaGroupWrapperActions, - UserGroupsWrapperActions, -} from '../webworker/workers/browser/libsession_worker_interface'; +import { UserGroupsWrapperActions } from '../webworker/workers/browser/libsession_worker_interface'; import { ConversationInteractionStatus, ConversationInteractionType } from './types'; import { BlockedNumberController } from '../util'; import { LocalizerComponentProps, LocalizerToken } from '../types/localizer'; import { sendInviteResponseToGroup } from '../session/sending/group/GroupInviteResponse'; import { NetworkTime } from '../util/NetworkTime'; -import { GroupSync } from '../session/utils/job_runners/jobs/GroupSyncJob'; export async function copyPublicKeyByConvoId(convoId: string) { if (OpenGroupUtils.isOpenGroupV2(convoId)) { @@ -136,17 +132,6 @@ export const handleAcceptConversationRequest = async ({ convoId }: { convoId: st if (!previousIsApproved) { await sendInviteResponseToGroup({ groupPk: convoId }); } - const refreshed = await UserGroupsWrapperActions.getGroup(convoId); - - // if we are admin, we also need to accept it and mark ourselves as such - const weAreAdmin = refreshed && !isEmpty(refreshed.secretKey); - if (weAreAdmin) { - await MetaGroupWrapperActions.memberSetPromotionAccepted( - convoId, - UserUtils.getOurPubKeyStrFromCache() - ); - await GroupSync.queueNewJobIfNeeded(convoId); - } window.log.info( `handleAcceptConversationRequest: first poll for group ${ed25519Str(convoId)} happened, we should have encryption keys now` diff --git a/ts/session/utils/job_runners/PersistedJob.ts b/ts/session/utils/job_runners/PersistedJob.ts index c6a9ef652..290f285d4 100644 --- a/ts/session/utils/job_runners/PersistedJob.ts +++ b/ts/session/utils/job_runners/PersistedJob.ts @@ -42,6 +42,7 @@ export interface GroupInvitePersistedData extends PersistedJobData { jobType: 'GroupInviteJobType'; groupPk: GroupPubkeyType; member: PubkeyType; + inviteAsAdmin: boolean; } export interface GroupPromotePersistedData extends PersistedJobData { diff --git a/ts/session/utils/job_runners/jobs/GroupInviteJob.ts b/ts/session/utils/job_runners/jobs/GroupInviteJob.ts index c339eeb60..747e8e284 100644 --- a/ts/session/utils/job_runners/jobs/GroupInviteJob.ts +++ b/ts/session/utils/job_runners/jobs/GroupInviteJob.ts @@ -28,6 +28,7 @@ const defaultMaxAttempts = 1; type JobExtraArgs = { groupPk: GroupPubkeyType; member: PubkeyType; + inviteAsAdmin: boolean; }; export function shouldAddJob(args: JobExtraArgs) { @@ -46,11 +47,12 @@ const invitesFailed = new Map< } >(); -async function addJob({ groupPk, member }: JobExtraArgs) { - if (shouldAddJob({ groupPk, member })) { +async function addJob({ groupPk, member, inviteAsAdmin }: JobExtraArgs) { + if (shouldAddJob({ groupPk, member, inviteAsAdmin })) { const groupInviteJob = new GroupInviteJob({ groupPk, member, + inviteAsAdmin, nextAttemptTimestamp: Date.now(), }); window.log.debug(`addGroupInviteJob: adding group invite for ${groupPk}:${member} `); @@ -123,11 +125,12 @@ class GroupInviteJob extends PersistedJob { constructor({ groupPk, member, + inviteAsAdmin, nextAttemptTimestamp, maxAttempts, currentRetry, identifier, - }: Pick & + }: Pick & Partial< Pick< GroupInvitePersistedData, @@ -143,6 +146,7 @@ class GroupInviteJob extends PersistedJob { identifier: identifier || v4(), member, groupPk, + inviteAsAdmin, delayBetweenRetries: defaultMsBetweenRetries, maxAttempts: isNumber(maxAttempts) ? maxAttempts : defaultMaxAttempts, nextAttemptTimestamp: nextAttemptTimestamp || Date.now() + defaultMsBetweenRetries, @@ -151,10 +155,10 @@ class GroupInviteJob extends PersistedJob { } public async run(): Promise { - const { groupPk, member, jobType, identifier } = this.persistedData; + const { groupPk, member, inviteAsAdmin, jobType, identifier } = this.persistedData; window.log.info( - `running job ${jobType} with groupPk:"${groupPk}" member: ${member} id:"${identifier}" ` + `running job ${jobType} with groupPk:"${groupPk}" member:${member} inviteAsAdmin:${inviteAsAdmin} id:"${identifier}" ` ); const group = await UserGroupsWrapperActions.getGroup(groupPk); if (!group || !group.secretKey || !group.name) { @@ -167,7 +171,7 @@ class GroupInviteJob extends PersistedJob { } let failed = true; try { - const inviteDetails = window.sessionFeatureFlags.useGroupV2InviteAsAdmin + const inviteDetails = inviteAsAdmin ? await SnodeGroupSignature.getGroupPromoteMessage({ groupName: group.name, member, @@ -200,6 +204,16 @@ class GroupInviteJob extends PersistedJob { ); try { await MetaGroupWrapperActions.memberSetInvited(groupPk, member, failed); + // Depending on this field, we either send an invite or an invite-as-admin message. + // When we do send an invite-as-admin we also need to update the promoted state, so that the invited members + // knows he needs to accept the promotion when accepting the invite + if (inviteAsAdmin) { + if (failed) { + await MetaGroupWrapperActions.memberSetPromotionFailed(groupPk, member); + } else { + await MetaGroupWrapperActions.memberSetPromotionSent(groupPk, member); + } + } } catch (e) { window.log.warn('GroupInviteJob memberSetInvited failed with', e.message); } diff --git a/ts/state/ducks/metaGroups.ts b/ts/state/ducks/metaGroups.ts index 1d9c5805a..928101a42 100644 --- a/ts/state/ducks/metaGroups.ts +++ b/ts/state/ducks/metaGroups.ts @@ -245,7 +245,11 @@ const initNewGroupInWrapper = createAsyncThunk( // can update the group wrapper with a failed state if a message fails to be sent. for (let index = 0; index < membersFromWrapper.length; index++) { const member = membersFromWrapper[index]; - await GroupInvite.addJob({ member: member.pubkeyHex, groupPk }); + await GroupInvite.addJob({ + member: member.pubkeyHex, + groupPk, + inviteAsAdmin: window.sessionFeatureFlags.useGroupV2InviteAsAdmin, + }); } await openConversationWithMessages({ conversationKey: groupPk, messageId: null }); @@ -773,7 +777,12 @@ async function handleMemberAddedFromUI({ } // schedule send invite details, auth signature, etc. to the new users - await scheduleGroupInviteJobs(groupPk, withHistory, withoutHistory); + await scheduleGroupInviteJobs( + groupPk, + withHistory, + withoutHistory, + window.sessionFeatureFlags.useGroupV2InviteAsAdmin + ); await LibSessionUtil.saveDumpsToDb(groupPk); convo.set({ @@ -1444,14 +1453,15 @@ export const groupReducer = metaGroupSlice.reducer; async function scheduleGroupInviteJobs( groupPk: GroupPubkeyType, withHistory: Array, - withoutHistory: Array + withoutHistory: Array, + inviteAsAdmin: boolean ) { for (let index = 0; index < withoutHistory.length; index++) { const member = withoutHistory[index]; - await GroupInvite.addJob({ groupPk, member }); + await GroupInvite.addJob({ groupPk, member, inviteAsAdmin }); } for (let index = 0; index < withHistory.length; index++) { const member = withHistory[index]; - await GroupInvite.addJob({ groupPk, member }); + await GroupInvite.addJob({ groupPk, member, inviteAsAdmin }); } }