fix: allow invite to be promote, and handle recipient side too

pull/3052/head
Audric Ackermann 6 months ago
parent 07930d4e5e
commit 8644db64bc
No known key found for this signature in database

@ -224,7 +224,11 @@ const ResendInviteButton = ({
buttonType={SessionButtonType.Solid} buttonType={SessionButtonType.Solid}
text={window.i18n('resend')} text={window.i18n('resend')}
onClick={() => { onClick={() => {
void GroupInvite.addJob({ groupPk, member: pubkey }); void GroupInvite.addJob({
groupPk,
member: pubkey,
inviteAsAdmin: window.sessionFeatureFlags.useGroupV2InviteAsAdmin,
});
}} }}
/> />
); );

@ -206,7 +206,7 @@ export const UpdateGroupMembersDialog = (props: Props) => {
} }
if (groupAdmins?.includes(member)) { if (groupAdmins?.includes(member)) {
if (PubKey.is03Pubkey(conversationId)) { 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; return;
} }
ToastUtils.pushCannotRemoveCreatorFromGroup(); ToastUtils.pushCannotRemoveCreatorFromGroup();

@ -1,4 +1,4 @@
import { isEmpty, isNil } from 'lodash'; import { isNil } from 'lodash';
import { import {
ConversationNotificationSettingType, ConversationNotificationSettingType,
READ_MESSAGE_STATE, READ_MESSAGE_STATE,
@ -47,16 +47,12 @@ import { urlToBlob } from '../types/attachments/VisualAttachment';
import { encryptProfile } from '../util/crypto/profileEncrypter'; import { encryptProfile } from '../util/crypto/profileEncrypter';
import { ReleasedFeatures } from '../util/releaseFeature'; import { ReleasedFeatures } from '../util/releaseFeature';
import { Storage, setLastProfileUpdateTimestamp } from '../util/storage'; import { Storage, setLastProfileUpdateTimestamp } from '../util/storage';
import { import { UserGroupsWrapperActions } from '../webworker/workers/browser/libsession_worker_interface';
MetaGroupWrapperActions,
UserGroupsWrapperActions,
} from '../webworker/workers/browser/libsession_worker_interface';
import { ConversationInteractionStatus, ConversationInteractionType } from './types'; import { ConversationInteractionStatus, ConversationInteractionType } from './types';
import { BlockedNumberController } from '../util'; import { BlockedNumberController } from '../util';
import { LocalizerComponentProps, LocalizerToken } from '../types/localizer'; import { LocalizerComponentProps, LocalizerToken } from '../types/localizer';
import { sendInviteResponseToGroup } from '../session/sending/group/GroupInviteResponse'; import { sendInviteResponseToGroup } from '../session/sending/group/GroupInviteResponse';
import { NetworkTime } from '../util/NetworkTime'; import { NetworkTime } from '../util/NetworkTime';
import { GroupSync } from '../session/utils/job_runners/jobs/GroupSyncJob';
export async function copyPublicKeyByConvoId(convoId: string) { export async function copyPublicKeyByConvoId(convoId: string) {
if (OpenGroupUtils.isOpenGroupV2(convoId)) { if (OpenGroupUtils.isOpenGroupV2(convoId)) {
@ -136,17 +132,6 @@ export const handleAcceptConversationRequest = async ({ convoId }: { convoId: st
if (!previousIsApproved) { if (!previousIsApproved) {
await sendInviteResponseToGroup({ groupPk: convoId }); 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( window.log.info(
`handleAcceptConversationRequest: first poll for group ${ed25519Str(convoId)} happened, we should have encryption keys now` `handleAcceptConversationRequest: first poll for group ${ed25519Str(convoId)} happened, we should have encryption keys now`

@ -42,6 +42,7 @@ export interface GroupInvitePersistedData extends PersistedJobData {
jobType: 'GroupInviteJobType'; jobType: 'GroupInviteJobType';
groupPk: GroupPubkeyType; groupPk: GroupPubkeyType;
member: PubkeyType; member: PubkeyType;
inviteAsAdmin: boolean;
} }
export interface GroupPromotePersistedData extends PersistedJobData { export interface GroupPromotePersistedData extends PersistedJobData {

@ -28,6 +28,7 @@ const defaultMaxAttempts = 1;
type JobExtraArgs = { type JobExtraArgs = {
groupPk: GroupPubkeyType; groupPk: GroupPubkeyType;
member: PubkeyType; member: PubkeyType;
inviteAsAdmin: boolean;
}; };
export function shouldAddJob(args: JobExtraArgs) { export function shouldAddJob(args: JobExtraArgs) {
@ -46,11 +47,12 @@ const invitesFailed = new Map<
} }
>(); >();
async function addJob({ groupPk, member }: JobExtraArgs) { async function addJob({ groupPk, member, inviteAsAdmin }: JobExtraArgs) {
if (shouldAddJob({ groupPk, member })) { if (shouldAddJob({ groupPk, member, inviteAsAdmin })) {
const groupInviteJob = new GroupInviteJob({ const groupInviteJob = new GroupInviteJob({
groupPk, groupPk,
member, member,
inviteAsAdmin,
nextAttemptTimestamp: Date.now(), nextAttemptTimestamp: Date.now(),
}); });
window.log.debug(`addGroupInviteJob: adding group invite for ${groupPk}:${member} `); window.log.debug(`addGroupInviteJob: adding group invite for ${groupPk}:${member} `);
@ -123,11 +125,12 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
constructor({ constructor({
groupPk, groupPk,
member, member,
inviteAsAdmin,
nextAttemptTimestamp, nextAttemptTimestamp,
maxAttempts, maxAttempts,
currentRetry, currentRetry,
identifier, identifier,
}: Pick<GroupInvitePersistedData, 'groupPk' | 'member'> & }: Pick<GroupInvitePersistedData, 'groupPk' | 'member' | 'inviteAsAdmin'> &
Partial< Partial<
Pick< Pick<
GroupInvitePersistedData, GroupInvitePersistedData,
@ -143,6 +146,7 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
identifier: identifier || v4(), identifier: identifier || v4(),
member, member,
groupPk, groupPk,
inviteAsAdmin,
delayBetweenRetries: defaultMsBetweenRetries, delayBetweenRetries: defaultMsBetweenRetries,
maxAttempts: isNumber(maxAttempts) ? maxAttempts : defaultMaxAttempts, maxAttempts: isNumber(maxAttempts) ? maxAttempts : defaultMaxAttempts,
nextAttemptTimestamp: nextAttemptTimestamp || Date.now() + defaultMsBetweenRetries, nextAttemptTimestamp: nextAttemptTimestamp || Date.now() + defaultMsBetweenRetries,
@ -151,10 +155,10 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
} }
public async run(): Promise<RunJobResult> { public async run(): Promise<RunJobResult> {
const { groupPk, member, jobType, identifier } = this.persistedData; const { groupPk, member, inviteAsAdmin, jobType, identifier } = this.persistedData;
window.log.info( 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); const group = await UserGroupsWrapperActions.getGroup(groupPk);
if (!group || !group.secretKey || !group.name) { if (!group || !group.secretKey || !group.name) {
@ -167,7 +171,7 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
} }
let failed = true; let failed = true;
try { try {
const inviteDetails = window.sessionFeatureFlags.useGroupV2InviteAsAdmin const inviteDetails = inviteAsAdmin
? await SnodeGroupSignature.getGroupPromoteMessage({ ? await SnodeGroupSignature.getGroupPromoteMessage({
groupName: group.name, groupName: group.name,
member, member,
@ -200,6 +204,16 @@ class GroupInviteJob extends PersistedJob<GroupInvitePersistedData> {
); );
try { try {
await MetaGroupWrapperActions.memberSetInvited(groupPk, member, failed); 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) { } catch (e) {
window.log.warn('GroupInviteJob memberSetInvited failed with', e.message); window.log.warn('GroupInviteJob memberSetInvited failed with', e.message);
} }

@ -245,7 +245,11 @@ const initNewGroupInWrapper = createAsyncThunk(
// can update the group wrapper with a failed state if a message fails to be sent. // can update the group wrapper with a failed state if a message fails to be sent.
for (let index = 0; index < membersFromWrapper.length; index++) { for (let index = 0; index < membersFromWrapper.length; index++) {
const member = membersFromWrapper[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 }); await openConversationWithMessages({ conversationKey: groupPk, messageId: null });
@ -773,7 +777,12 @@ async function handleMemberAddedFromUI({
} }
// schedule send invite details, auth signature, etc. to the new users // 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); await LibSessionUtil.saveDumpsToDb(groupPk);
convo.set({ convo.set({
@ -1444,14 +1453,15 @@ export const groupReducer = metaGroupSlice.reducer;
async function scheduleGroupInviteJobs( async function scheduleGroupInviteJobs(
groupPk: GroupPubkeyType, groupPk: GroupPubkeyType,
withHistory: Array<PubkeyType>, withHistory: Array<PubkeyType>,
withoutHistory: Array<PubkeyType> withoutHistory: Array<PubkeyType>,
inviteAsAdmin: boolean
) { ) {
for (let index = 0; index < withoutHistory.length; index++) { for (let index = 0; index < withoutHistory.length; index++) {
const member = withoutHistory[index]; const member = withoutHistory[index];
await GroupInvite.addJob({ groupPk, member }); await GroupInvite.addJob({ groupPk, member, inviteAsAdmin });
} }
for (let index = 0; index < withHistory.length; index++) { for (let index = 0; index < withHistory.length; index++) {
const member = withHistory[index]; const member = withHistory[index];
await GroupInvite.addJob({ groupPk, member }); await GroupInvite.addJob({ groupPk, member, inviteAsAdmin });
} }
} }

Loading…
Cancel
Save