feat: mark us as admin and others as invite pending

pull/2873/head
Audric Ackermann 2 years ago
parent 197383a52f
commit 9191c3476d

@ -12,6 +12,7 @@ import { StateType } from '../state/reducer';
import { getMessageReactsProps } from '../state/selectors/conversations';
import { useLibGroupAdmins, useLibGroupMembers, useLibGroupName } from '../state/selectors/groups';
import { isPrivateAndFriend } from '../state/selectors/selectedConversation';
import { useOurPkStr } from '../state/selectors/user';
export function useAvatarPath(convoId: string | undefined) {
const convoProps = useConversationPropsById(convoId);
@ -148,8 +149,9 @@ export function useIsKickedFromGroup(convoId?: string) {
}
export function useWeAreAdmin(convoId?: string) {
const convoProps = useConversationPropsById(convoId);
return Boolean(convoProps && convoProps.weAreAdmin);
const groupAdmins = useGroupAdmins(convoId);
const us = useOurPkStr();
return Boolean(groupAdmins.includes(us));
}
export function useGroupAdmins(convoId?: string) {
@ -221,7 +223,8 @@ export function useIsOutgoingRequest(convoId?: string) {
}
/**
* Not to be exported: This selector is too generic and needs to be broken node in individual fields selectors.
* Note: NOT to be exported:
* This selector is too generic and needs to be broken node in individual fields selectors.
* Make sure when writing a selector that you fetch the data from libsession if needed.
* (check useSortedGroupMembers() as an example)
*/

@ -42,9 +42,6 @@ async function handleGroupSharedConfigMessages(
groupKeys: keys,
groupMember: members,
};
console.info(
`groupInfo before merge: ${stringify(await MetaGroupWrapperActions.infoGet(groupPk))}`
);
await MetaGroupWrapperActions.metaMerge(groupPk, toMerge);
await LibSessionUtil.saveMetaGroupDumpToDb(groupPk);

@ -1,4 +1,4 @@
import _ from 'lodash';
import _, { concat } from 'lodash';
import { ClosedGroup, getMessageQueue } from '..';
import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { addKeyPairToCacheAndDBIfNeeded } from '../../receiver/closedGroups';
@ -26,10 +26,14 @@ import { groupInfoActions } from '../../state/ducks/groups';
*/
export async function createClosedGroup(groupName: string, members: Array<string>, isV3: boolean) {
if (isV3) {
const us = UserUtils.getOurPubKeyStrFromCache();
// we need to send a group info and encryption keys message to the batch endpoint with both seqno being 0
console.error('isV3 send invite to group TODO'); // FIXME
// FIXME we should save the key to the wrapper right away? or even to the DB idk
window.inboxStore.dispatch(groupInfoActions.initNewGroupInWrapper({ members, groupName }));
window.inboxStore.dispatch(
groupInfoActions.initNewGroupInWrapper({ members: concat(members, [us]), groupName, us })
);
return;
}

@ -1,6 +1,6 @@
import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { GroupInfoGet, GroupMemberGet, GroupPubkeyType } from 'libsession_util_nodejs';
import { isEmpty } from 'lodash';
import { isEmpty, uniq } from 'lodash';
import { ConfigDumpData } from '../../data/configDump/configDump';
import { ConversationTypeEnum } from '../../models/conversationAttributes';
import { HexString } from '../../node/hexStrings';
@ -16,6 +16,7 @@ import {
MetaGroupWrapperActions,
UserGroupsWrapperActions,
} from '../../webworker/workers/browser/libsession_worker_interface';
import { PreConditionFailed } from '../../session/utils/errors';
export type GroupState = {
infos: Record<GroupPubkeyType, GroupInfoGet>;
@ -35,12 +36,23 @@ type GroupDetailsUpdate = {
const initNewGroupInWrapper = createAsyncThunk(
'group/initNewGroupInWrapper',
async (groupDetails: {
async ({
groupName,
members,
us,
}: {
groupName: string;
members: Array<string>;
us: string;
}): Promise<GroupDetailsUpdate> => {
if (!members.includes(us)) {
throw new PreConditionFailed('initNewGroupInWrapper needs us to be a member');
}
const uniqMembers = uniq(members);
try {
const newGroup = await UserGroupsWrapperActions.createGroup();
const groupPk = newGroup.pubkeyHex;
newGroup.name = groupName; // this will be used by the linked devices until they fetch the info from the groups swarm
await UserGroupsWrapperActions.setGroup(newGroup);
@ -49,47 +61,42 @@ const initNewGroupInWrapper = createAsyncThunk(
throw new Error('Current user has no priv ed25519 key?');
}
const userEd25519Secretkey = ourEd25519KeypairBytes.privKeyBytes;
const groupEd2519Pk = HexString.fromHexString(newGroup.pubkeyHex).slice(1); // remove the 03 prefix (single byte once in hex form)
const groupEd2519Pk = HexString.fromHexString(groupPk).slice(1); // remove the 03 prefix (single byte once in hex form)
// dump is always empty when creating a new groupInfo
await MetaGroupWrapperActions.init(newGroup.pubkeyHex, {
await MetaGroupWrapperActions.init(groupPk, {
metaDumped: null,
userEd25519Secretkey: toFixedUint8ArrayOfLength(userEd25519Secretkey, 64),
groupEd25519Secretkey: newGroup.secretKey,
groupEd25519Pubkey: toFixedUint8ArrayOfLength(groupEd2519Pk, 32),
});
await Promise.all(
groupDetails.members.map(async member => {
const created = await MetaGroupWrapperActions.memberGetOrConstruct(
newGroup.pubkeyHex,
member
);
await MetaGroupWrapperActions.memberSetInvited(
newGroup.pubkeyHex,
created.pubkeyHex,
false
);
})
);
const infos = await MetaGroupWrapperActions.infoGet(newGroup.pubkeyHex);
for (let index = 0; index < uniqMembers.length; index++) {
const member = uniqMembers[index];
const created = await MetaGroupWrapperActions.memberGetOrConstruct(groupPk, member);
if (created.pubkeyHex === us) {
await MetaGroupWrapperActions.memberSetPromoted(groupPk, created.pubkeyHex, false);
} else {
await MetaGroupWrapperActions.memberSetInvited(groupPk, created.pubkeyHex, false);
}
}
const infos = await MetaGroupWrapperActions.infoGet(groupPk);
if (!infos) {
throw new Error(
`getInfos of ${newGroup.pubkeyHex} returned empty result even if it was just init.`
);
throw new Error(`getInfos of ${groupPk} returned empty result even if it was just init.`);
}
infos.name = groupDetails.groupName;
await MetaGroupWrapperActions.infoSet(newGroup.pubkeyHex, infos);
infos.name = groupName;
await MetaGroupWrapperActions.infoSet(groupPk, infos);
const members = await MetaGroupWrapperActions.memberGetAll(newGroup.pubkeyHex);
if (!members || isEmpty(members)) {
const membersFromWrapper = await MetaGroupWrapperActions.memberGetAll(groupPk);
if (!membersFromWrapper || isEmpty(membersFromWrapper)) {
throw new Error(
`memberGetAll of ${newGroup.pubkeyHex} returned empty result even if it was just init.`
`memberGetAll of ${groupPk} returned empty result even if it was just init.`
);
}
const convo = await getConversationController().getOrCreateAndWait(
newGroup.pubkeyHex,
groupPk,
ConversationTypeEnum.GROUPV3
);
@ -99,11 +106,7 @@ const initNewGroupInWrapper = createAsyncThunk(
// // the sync below will need the secretKey of the group to be saved in the wrapper. So save it!
await UserGroupsWrapperActions.setGroup(newGroup);
await GroupSync.queueNewJobIfNeeded(newGroup.pubkeyHex);
// const us = UserUtils.getOurPubKeyStrFromCache();
// // Ensure the current user is a member and admin
// const members = uniq([...groupDetails.members, us]);
await GroupSync.queueNewJobIfNeeded(groupPk);
// const updateGroupDetails: ClosedGroup.GroupInfo = {
// id: newGroup.pubkeyHex,
@ -122,7 +125,7 @@ const initNewGroupInWrapper = createAsyncThunk(
await convo.commit();
convo.updateLastMessage();
return { groupPk: newGroup.pubkeyHex, infos, members };
return { groupPk: newGroup.pubkeyHex, infos, members: membersFromWrapper };
} catch (e) {
throw e;
}

@ -4,6 +4,7 @@ import { LocalizerType } from '../../types/Util';
import { StateType } from '../reducer';
import { UserStateType } from '../ducks/user';
import { useSelector } from 'react-redux';
export const getUser = (state: StateType): UserStateType => state.user;
@ -13,3 +14,7 @@ export const getOurNumber = createSelector(
);
export const getIntl = createSelector(getUser, (): LocalizerType => window.i18n);
export function useOurPkStr() {
return useSelector((state: StateType) => getOurNumber(state));
}

Loading…
Cancel
Save