feat: remove closedgroupv3 uneeded stuff for now

also move the room stuff which can be kept in memory into another redux
slice
pull/2620/head
Audric Ackermann 2 years ago
parent 2a5dc5f2a5
commit f5efb52fea

@ -31,6 +31,7 @@ import { ExpirationTimerOptions } from '../util/expiringMessages';
// moment does not support es-419 correctly (and cause white screen on app start)
import moment from 'moment';
import styled from 'styled-components';
import { initialSogsRoomInfoState } from '../state/ducks/sogsRoomInfo';
// Default to the locale from env. It will be overriden if moment
// does not recognize it with what moment knows which is the closest.
@ -117,11 +118,15 @@ export class SessionInboxView extends React.Component<any, State> {
},
stagedAttachments: getEmptyStagedAttachmentsState(),
call: initialCallState,
sogsRoomInfo: initialSogsRoomInfoState,
};
this.store = createStore(initialState);
window.inboxStore = this.store;
console.warn('initialState', JSON.stringify(initialState));
console.warn('this.store', JSON.stringify(this.store.getState()));
window.openConversationWithMessages = openConversationWithMessages;
this.setState({ isInitialLoadComplete: true });

@ -8,6 +8,7 @@ import { ConversationNotificationSettingType } from '../../models/conversationAt
import {
getConversationHeaderTitleProps,
getCurrentNotificationSettingText,
getCurrentSubscriberCount,
getIsSelectedActive,
getIsSelectedBlocked,
getIsSelectedNoteToSelf,
@ -55,37 +56,6 @@ export interface TimerOption {
value: number;
}
export type ConversationHeaderProps = {
conversationKey: string;
name?: string;
profileName?: string;
avatarPath: string | null;
isMe: boolean;
isGroup: boolean;
isPrivate: boolean;
isPublic: boolean;
weAreAdmin: boolean;
// We might not always have the full list of members,
// e.g. for open groups where we could have thousands
// of members. We'll keep this for now (for closed chats)
members: Array<any>;
// not equal members.length (see above)
subscriberCount?: number;
expirationSettingName?: string;
currentNotificationSetting: ConversationNotificationSettingType;
hasNickname: boolean;
isBlocked: boolean;
isKickedFromGroup: boolean;
left: boolean;
};
const SelectionOverlay = () => {
const selectedMessageIds = useSelector(getSelectedMessageIds);
const selectedConversationKey = useSelector(getSelectedConversationKey);
@ -276,7 +246,6 @@ export type ConversationHeaderTitleProps = {
isGroup: boolean;
isPublic: boolean;
members: Array<any>;
subscriberCount?: number;
isKickedFromGroup: boolean;
currentNotificationSetting?: ConversationNotificationSettingType;
};
@ -295,17 +264,19 @@ export const ConversationHeaderSubtitle = (props: { text?: string | null }): JSX
};
const ConversationHeaderTitle = () => {
const dispatch = useDispatch();
const headerTitleProps = useSelector(getConversationHeaderTitleProps);
const notificationSetting = useSelector(getCurrentNotificationSettingText);
const isRightPanelOn = useSelector(isRightPanelShowing);
const convoName = useConversationUsername(headerTitleProps?.conversationKey);
const dispatch = useDispatch();
const subscriberCount = useSelector(getCurrentSubscriberCount);
if (!headerTitleProps) {
return null;
}
const { isGroup, isPublic, members, subscriberCount, isMe, isKickedFromGroup } = headerTitleProps;
const { isGroup, isPublic, members, isMe, isKickedFromGroup } = headerTitleProps;
const { i18n } = window;

@ -17,7 +17,11 @@ import {
} from '../../interactions/conversationInteractions';
import { Constants } from '../../session';
import { closeRightPanel } from '../../state/ducks/conversations';
import { getSelectedConversation, isRightPanelShowing } from '../../state/selectors/conversations';
import {
getCurrentSubscriberCount,
getSelectedConversation,
isRightPanelShowing,
} from '../../state/selectors/conversations';
import { getTimerOptions } from '../../state/selectors/timerOptions';
import { AttachmentTypeWithPath } from '../../types/Attachment';
import { Avatar, AvatarSize } from '../avatar/Avatar';
@ -189,6 +193,7 @@ export const SessionRightPanelWithDetails = () => {
const selectedConversation = useSelector(getSelectedConversation);
const isShowing = useSelector(isRightPanelShowing);
const subscriberCount = useSelector(getCurrentSubscriberCount);
useEffect(() => {
let isRunning = true;
@ -229,7 +234,6 @@ export const SessionRightPanelWithDetails = () => {
const {
id,
subscriberCount,
displayNameInProfile,
isKickedFromGroup,
left,

@ -80,6 +80,8 @@ import { ed25519Str } from '../session/onions/onionPath';
import { ConfigurationDumpSync } from '../session/utils/job_runners/jobs/ConfigurationSyncDumpJob';
import { ConfigurationSync } from '../session/utils/job_runners/jobs/ConfigurationSyncJob';
import { SessionUtilContact } from '../session/utils/libsession/libsession_utils_contacts';
import { SessionUtilConvoInfoVolatile } from '../session/utils/libsession/libsession_utils_convo_info_volatile';
import { SessionUtilUserGroups } from '../session/utils/libsession/libsession_utils_user_groups';
import { forceSyncConfigurationNowIfNeeded } from '../session/utils/sync/syncUtils';
import { getOurProfile } from '../session/utils/User';
import { createLastMessageUpdate } from '../types/Conversation';
@ -90,8 +92,10 @@ import {
} from '../types/MessageAttachment';
import { IMAGE_JPEG } from '../types/MIME';
import { Reaction } from '../types/Reaction';
import { assertUnreachable } from '../types/sqlSharedTypes';
import { Notifications } from '../util/notifications';
import { Reactions } from '../util/reactions';
import { Registration } from '../util/registration';
import { Storage } from '../util/storage';
import {
ConversationAttributes,
@ -101,13 +105,14 @@ import {
isDirectConversation,
isOpenOrClosedGroup,
} from './conversationAttributes';
import { SessionUtilUserGroups } from '../session/utils/libsession/libsession_utils_user_groups';
import { Registration } from '../util/registration';
import { SessionUtilConvoInfoVolatile } from '../session/utils/libsession/libsession_utils_convo_info_volatile';
import { assertUnreachable } from '../types/sqlSharedTypes';
import { LibSessionUtil } from '../session/utils/libsession/libsession_utils';
import { SessionUtilUserProfile } from '../session/utils/libsession/libsession_utils_user_profile';
import { ReduxSogsRoomInfos } from '../state/ducks/sogsRoomInfo';
import {
getCanWriteOutsideRedux,
getSubscriberCountOutsideRedux,
} from '../state/selectors/sogsRoomInfo';
export class ConversationModel extends Backbone.Model<ConversationAttributes> {
public updateLastMessage: () => any;
@ -307,7 +312,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const isTyping = !!this.typingTimer;
const unreadCount = this.get('unreadCount') || undefined;
const mentionedUs = this.get('mentionedUs') || undefined;
const subscriberCount = this.get('subscriberCount');
const isKickedFromGroup = !!this.get('isKickedFromGroup');
const left = !!this.get('left');
const expireTimer = this.get('expireTimer');
@ -435,10 +439,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
toRet.left = left;
}
if (subscriberCount) {
toRet.subscriberCount = subscriberCount;
}
if (groupAdmins && groupAdmins.length) {
toRet.groupAdmins = uniq(groupAdmins);
}
@ -471,16 +471,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (room && isArray(room.capabilities) && room.capabilities.length) {
toRet.capabilities = room.capabilities;
}
if (this.get('writeCapability')) {
toRet.writeCapability = this.get('writeCapability');
}
if (this.get('readCapability')) {
toRet.readCapability = this.get('readCapability');
}
if (this.get('uploadCapability')) {
toRet.uploadCapability = this.get('uploadCapability');
}
}
const lastMessageText = this.get('lastMessage');
@ -1375,13 +1365,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
read = filter(read, m => Boolean(m.sender));
const realUnreadCount = await this.getUnreadCount();
if (read.length === 0) {
const cachedUnreadCountOnConvo = this.get('unreadCount');
if (cachedUnreadCountOnConvo !== realUnreadCount) {
if (this.get('unreadCount') !== realUnreadCount) {
// reset the unreadCount on the convo to the real one coming from markRead messages on the db
this.set({ unreadCount: realUnreadCount });
await this.commit();
} else {
// window?.log?.info('markRead(): nothing newly read.');
}
return;
}
@ -1624,21 +1611,13 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
await this.commit();
}
public async setSubscriberCount(count: number) {
if (this.get('subscriberCount') !== count) {
this.set({ subscriberCount: count });
await this.commit();
}
// Not sure if we care about updating the database
}
/**
* Saves the infos of that room directly on the conversation table.
* This does not write anything to the db if no changes are detected
*/
// tslint:disable-next-line: cyclomatic-complexity
public async setPollInfo(infos?: {
subscriberCount: number;
active_users: number;
read: boolean;
write: boolean;
upload: boolean;
@ -1655,29 +1634,18 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return;
}
let hasChange = false;
const { read, write, upload, subscriberCount, details } = infos;
const { write, active_users, details } = infos;
if (
isNumber(infos.subscriberCount) &&
infos.subscriberCount !== 0 &&
this.get('subscriberCount') !== subscriberCount
isFinite(infos.active_users) &&
infos.active_users !== 0 &&
getSubscriberCountOutsideRedux(this.id) !== active_users
) {
hasChange = true;
this.set('subscriberCount', subscriberCount);
}
if (Boolean(this.get('readCapability')) !== Boolean(read)) {
hasChange = true;
this.set('readCapability', Boolean(read));
}
if (Boolean(this.get('writeCapability')) !== Boolean(write)) {
hasChange = true;
this.set('writeCapability', Boolean(write));
ReduxSogsRoomInfos.setSubscriberCountOutsideRedux(this.id, active_users);
}
if (Boolean(this.get('uploadCapability')) !== Boolean(upload)) {
hasChange = true;
this.set('uploadCapability', Boolean(upload));
if (getCanWriteOutsideRedux(this.id) !== !!write) {
ReduxSogsRoomInfos.setCanWriteOutsideRedux(this.id, !!write);
}
const adminChanged = await this.handleModsOrAdminsChanges({

@ -36,6 +36,14 @@ export function isDirectConversation(conversationType: ConversationTypeEnum) {
export const ConversationNotificationSetting = ['all', 'disabled', 'mentions_only'] as const;
export type ConversationNotificationSettingType = typeof ConversationNotificationSetting[number];
/**
* Soem fields are retrieved from the database as a select, but should not be saved in a commit()
*/
export type ConversationAttributesNotSaved = {
mentionedUs: boolean;
unreadCount: number;
};
export interface ConversationAttributes {
id: string;
type: ConversationTypeEnum.PRIVATE | ConversationTypeEnum.GROUPV3 | ConversationTypeEnum.GROUP;
@ -68,11 +76,6 @@ export interface ConversationAttributes {
groupModerators: Array<string>; // for sogs only, this is the moderator in that room.
isKickedFromGroup: boolean;
subscriberCount: number;
readCapability: boolean;
writeCapability: boolean;
uploadCapability: boolean;
is_medium_group: boolean;
avatarPointer?: string; // this is the url of the avatar on the file server v2. we use this to detect if we need to redownload the avatar from someone (not used for opengroups)
@ -90,11 +93,6 @@ export interface ConversationAttributes {
markedAsUnread: boolean;
/**
* When we create a closed group v3 or get promoted to admim, we need to save the private key of that closed group.
*/
// identityPrivateKey?: string;
hidden: boolean;
}
@ -114,7 +112,6 @@ export const fillConvoAttributesWithDefaults = (
unreadCount: 0,
lastJoinedTimestamp: 0,
subscriberCount: 0,
expireTimer: 0,
active_at: 0,

@ -61,10 +61,6 @@ const allowedKeysFormatRowOfConversation = [
'triggerNotificationsFor',
'unreadCount',
'lastJoinedTimestamp',
'subscriberCount',
'readCapability',
'writeCapability',
'uploadCapability',
'expireTimer',
'active_at',
'id',
@ -76,12 +72,14 @@ const allowedKeysFormatRowOfConversation = [
'avatarInProfile',
'displayNameInProfile',
'conversationIdOrigin',
'identityPrivateKey',
'markedAsUnread',
'hidden',
];
// tslint:disable: cyclomatic-complexity
export function formatRowOfConversation(row?: Record<string, any>): ConversationAttributes | null {
export function formatRowOfConversation(
row: Record<string, any>,
from: string
): ConversationAttributes | null {
if (!row) {
return null;
}
@ -93,7 +91,7 @@ export function formatRowOfConversation(row?: Record<string, any>): Conversation
if (foundInRowButNotInAllowed?.length) {
console.error(
'formatRowOfConversation: foundInRowButNotInAllowed: ',
`formatRowOfConversation: "from:${from}" foundInRowButNotInAllowed: `,
foundInRowButNotInAllowed
);
@ -131,9 +129,6 @@ export function formatRowOfConversation(row?: Record<string, any>): Conversation
convo.mentionedUs = Boolean(convo.mentionedUs);
convo.isKickedFromGroup = Boolean(convo.isKickedFromGroup);
convo.left = Boolean(convo.left);
convo.readCapability = Boolean(convo.readCapability);
convo.writeCapability = Boolean(convo.writeCapability);
convo.uploadCapability = Boolean(convo.uploadCapability);
convo.markedAsUnread = Boolean(convo.markedAsUnread);
convo.hidden = Boolean(convo.hidden);
@ -161,10 +156,6 @@ export function formatRowOfConversation(row?: Record<string, any>): Conversation
convo.lastJoinedTimestamp = 0;
}
if (!convo.subscriberCount) {
convo.subscriberCount = 0;
}
if (!convo.expireTimer) {
convo.expireTimer = 0;
}
@ -173,11 +164,6 @@ export function formatRowOfConversation(row?: Record<string, any>): Conversation
convo.active_at = 0;
}
// convo.identityPrivateKey = row.identityPrivateKey;
// if (!convo.identityPrivateKey) {
// convo.identityPrivateKey = undefined;
// }
return convo;
}
@ -199,10 +185,6 @@ const allowedKeysOfConversationAttributes = [
'triggerNotificationsFor',
'unreadCount',
'lastJoinedTimestamp',
'subscriberCount',
'readCapability',
'writeCapability',
'uploadCapability',
'expireTimer',
'active_at',
'id',
@ -214,7 +196,6 @@ const allowedKeysOfConversationAttributes = [
'avatarInProfile',
'displayNameInProfile',
'conversationIdOrigin',
'identityPrivateKey',
'markedAsUnread',
'hidden',
];

@ -96,7 +96,6 @@ const LOKI_SCHEMA_VERSIONS = [
updateToSessionSchemaVersion28,
updateToSessionSchemaVersion29,
updateToSessionSchemaVersion30,
updateToSessionSchemaVersion31,
];
function updateToSessionSchemaVersion1(currentVersion: number, db: BetterSqlite3.Database) {
@ -604,23 +603,26 @@ function updateToSessionSchemaVersion20(currentVersion: number, db: BetterSqlite
console.info('found column friendRequestStatus. Dropping it');
db.exec(`ALTER TABLE ${CONVERSATIONS_TABLE} DROP COLUMN friendRequestStatus;`);
}
// disable those updates as sqlNode.saveConversation will break if called without the right type of arguments.
// and when called during a migration we won't have the expected arguments. Plus, this migration is almost a year old already
// looking for all private conversations, with a nickname set
const rowsToUpdate = db
.prepare(
`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND (name IS NULL or name = '') AND json_extract(json, '$.nickname') <> '';`
)
.all();
// const rowsToUpdate = db
// .prepare(
// `SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND (name IS NULL or name = '') AND json_extract(json, '$.nickname') <> '';`
// )
// .all();
// tslint:disable-next-line: no-void-expression
(rowsToUpdate || []).forEach(r => {
const obj = jsonToObject(r.json);
// obj.profile.displayName is the display as this user set it.
if (obj?.nickname?.length && obj?.profile?.displayName?.length) {
// this one has a nickname set, but name is unset, set it to the displayName in the lokiProfile if it's exisitng
obj.name = obj.profile.displayName;
sqlNode.saveConversation(obj as ConversationAttributes, db);
}
});
// (rowsToUpdate || []).forEach(r => {
// const obj = jsonToObject(r.json);
// // obj.profile.displayName is the display as this user set it.
// if (obj?.nickname?.length && obj?.profile?.displayName?.length) {
// // this one has a nickname set, but name is unset, set it to the displayName in the lokiProfile if it's exisitng
// obj.name = obj.profile.displayName;
// sqlNode.saveConversation(obj as ConversationAttributes, db);
// }
// });
writeSessionSchemaVersion(targetVersion, db);
});
console.log(`updateToSessionSchemaVersion${targetVersion}: success!`);
@ -1203,24 +1205,6 @@ function updateToSessionSchemaVersion29(currentVersion: number, db: BetterSqlite
console.log(`updateToSessionSchemaVersion${targetVersion}: success!`);
}
function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite3.Database) {
const targetVersion = 30;
if (currentVersion >= targetVersion) {
return;
}
console.log(`updateToSessionSchemaVersion${targetVersion}: starting...`);
// this column will only be set when this is a closed group v3 and we are the admin/got promoted to admin
db.transaction(() => {
db.exec(`ALTER TABLE ${CONVERSATIONS_TABLE}
ADD COLUMN identityPrivateKey TEXT;
`);
writeSessionSchemaVersion(targetVersion, db);
})();
console.log(`updateToSessionSchemaVersion${targetVersion}: success!`);
}
function getIdentityKeysDuringMigration(db: BetterSqlite3.Database) {
const row = db.prepare(`SELECT * FROM ${ITEMS_TABLE} WHERE id = $id;`).get({
id: 'identityKey',
@ -1426,8 +1410,8 @@ function getBlockedNumbersDuringMigration(db: BetterSqlite3.Database) {
}
}
function updateToSessionSchemaVersion31(currentVersion: number, db: BetterSqlite3.Database) {
const targetVersion = 31;
function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite3.Database) {
const targetVersion = 30;
if (currentVersion >= targetVersion) {
return;
}
@ -1442,8 +1426,16 @@ function updateToSessionSchemaVersion31(currentVersion: number, db: BetterSqlite
db.exec(
`ALTER TABLE ${CONVERSATIONS_TABLE} ADD COLUMN hidden INTEGER NOT NULL DEFAULT ${toSqliteBoolean(
true
)} ;`
)};
`
);
// drop unused readCapability & uploadCapability columns. Also move `writeCapability` to memory only value.
db.exec(`
ALTER TABLE ${CONVERSATIONS_TABLE} DROP COLUMN readCapability;
ALTER TABLE ${CONVERSATIONS_TABLE} DROP COLUMN writeCapability;
ALTER TABLE ${CONVERSATIONS_TABLE} DROP COLUMN uploadCapability;
ALTER TABLE ${CONVERSATIONS_TABLE} DROP COLUMN subscriberCount;
`);
// mark every "active" private chats as not hidden
db.prepare(
`UPDATE ${CONVERSATIONS_TABLE} SET

@ -428,10 +428,6 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
groupAdmins,
groupModerators,
isKickedFromGroup,
subscriberCount,
readCapability,
writeCapability,
uploadCapability,
is_medium_group,
avatarPointer,
avatarImageId,
@ -444,11 +440,10 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
displayNameInProfile,
conversationIdOrigin,
hidden,
// identityPrivateKey,
markedAsUnread,
} = formatted;
console.warn('FIXME omit(formatted, identityPrivateKey);');
const omited = omit(formatted, 'identityPrivateKey', 'markedAsUnread');
const omited = omit(formatted);
const keys = Object.keys(omited);
const columnsCommaSeparated = keys.join(', ');
const valuesArgs = keys.map(k => `$${k}`).join(', ');
@ -488,10 +483,6 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
groupModerators:
groupModerators && groupModerators.length ? arrayStrToJson(groupModerators) : '[]',
isKickedFromGroup: toSqliteBoolean(isKickedFromGroup),
subscriberCount,
readCapability: toSqliteBoolean(readCapability),
writeCapability: toSqliteBoolean(writeCapability),
uploadCapability: toSqliteBoolean(uploadCapability),
is_medium_group: toSqliteBoolean(is_medium_group),
avatarPointer,
@ -504,8 +495,8 @@ function saveConversation(data: ConversationAttributes, instance?: BetterSqlite3
avatarInProfile,
displayNameInProfile,
conversationIdOrigin,
// identityPrivateKey,
hidden,
markedAsUnread: toSqliteBoolean(markedAsUnread),
});
}
@ -536,14 +527,14 @@ function getConversationById(id: string, instance?: BetterSqlite3.Database) {
id,
});
return formatRowOfConversation(row);
return formatRowOfConversation(row, 'getConversationById');
}
function getAllConversations() {
const rows = assertGlobalInstance()
.prepare(`SELECT * FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;`)
.all();
return (rows || []).map(formatRowOfConversation);
return (rows || []).map(m => formatRowOfConversation(m, 'getAllConversations'));
}
function getPubkeysInPublicConversation(conversationId: string) {
@ -590,7 +581,7 @@ function searchConversations(query: string) {
limit: 50,
});
return (rows || []).map(formatRowOfConversation);
return (rows || []).map(m => formatRowOfConversation(m, 'searchConversations'));
}
// order by clause is the same as orderByClause but with a table prefix so we cannot reuse it
@ -1089,9 +1080,7 @@ function getUnreadCountByConversation(conversationId: string) {
});
if (!row) {
throw new Error(
`getUnreadCountByConversation: Unable to get unread count of ${conversationId}`
);
throw new Error(`Unable to get unread count of ${conversationId}`);
}
return row['count(*)'];
@ -2131,12 +2120,15 @@ function cleanUpOldOpengroupsOnStart() {
start}ms. Old message count: ${messagesInConvoBefore}, new message count: ${messagesInConvoAfter}`
);
const unreadCount = getUnreadCountByConversation(convoId);
const convoProps = getConversationById(convoId);
if (convoProps) {
convoProps.unreadCount = unreadCount;
saveConversation(convoProps);
}
// no need to update the `unreadCount` during the migration anymore.
// `saveConversation` is broken when called with a argument without all the required fields.
// and this makes little sense as the unreadCount will be updated on opening
// const unreadCount = getUnreadCountByConversation(convoId);
// const convoProps = getConversationById(convoId);
// if (convoProps) {
// convoProps.unreadCount = unreadCount;
// saveConversation(convoProps);
// }
} else {
console.info(
`Not cleaning messages older than 6 months in public convo: ${convoId}. message count: ${messagesInConvoBefore}`

@ -9,13 +9,14 @@ import { Data } from '../../ts/data/data';
import { SignalService } from '../protobuf';
import { UserUtils } from '../session/utils';
import { showMessageRequestBanner } from '../state/ducks/userConfig';
import { showMessageRequestBannerOutsideRedux } from '../state/ducks/userConfig';
import { MessageDirection } from '../models/messageType';
import { LinkPreviews } from '../util/linkPreviews';
import { GoogleChrome } from '../util';
import { ConversationTypeEnum } from '../models/conversationAttributes';
import { getUsBlindedInThatServer } from '../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { ProfileManager } from '../session/profile_manager/ProfileManager';
import { getHideMessageRequestBannerOutsideRedux } from '../state/selectors/userConfig';
function contentTypeSupported(type: string): boolean {
const Chrome = GoogleChrome;
@ -258,9 +259,9 @@ async function handleRegularMessage(
if (
conversation.isIncomingRequest() &&
isFirstRequestMessage &&
window.inboxStore?.getState().userConfig.hideMessageRequests
getHideMessageRequestBannerOutsideRedux()
) {
window.inboxStore?.dispatch(showMessageRequestBanner());
showMessageRequestBannerOutsideRedux();
}
// For edge case when messaging a client that's unable to explicitly send request approvals

@ -119,7 +119,7 @@ async function handlePollInfoResponse(
read,
write,
upload,
subscriberCount: active_users,
active_users: active_users,
details: pick(
details,
'admins',

@ -25,6 +25,10 @@ import { getConversationController } from './ConversationController';
export async function createClosedGroup(groupName: string, members: Array<string>, isV3: boolean) {
const setOfMembers = new Set(members);
if (isV3) {
throw new Error('groupv3 is not supported yet');
}
const us = UserUtils.getOurPubKeyStrFromCache();
const identityKeyPair = await generateGroupV3Keypair();
@ -63,17 +67,6 @@ export async function createClosedGroup(groupName: string, members: Array<string
expireTimer: existingExpireTimer,
};
const groupDetailsV3: ClosedGroup.GroupInfoV3 = {
id: groupPublicKey,
identityPrivateKey: isV3 ? identityKeyPair.privateKey : undefined,
isV3: true,
name: groupName,
members: listOfMembers,
admins,
activeAt: Date.now(),
expireTimer: existingExpireTimer,
};
// used for UI only, adding of a message to remind who is in the group and the name of the group
const groupDiff: ClosedGroup.GroupDiff = {
newName: groupName,
@ -83,7 +76,7 @@ export async function createClosedGroup(groupName: string, members: Array<string
const dbMessage = await ClosedGroup.addUpdateMessage(convo, groupDiff, us, Date.now());
// be sure to call this before sending the message.
// the sending pipeline needs to know from GroupUtils when a message is for a medium group
await ClosedGroup.updateOrCreateClosedGroup(isV3 ? groupDetailsV3 : groupDetails);
await ClosedGroup.updateOrCreateClosedGroup(groupDetails);
await convo.commit();
convo.updateLastMessage();

@ -43,19 +43,6 @@ export type GroupInfo = {
weWereJustAdded?: boolean;
};
export type GroupInfoV3 = {
id: string;
identityPrivateKey?: string; // only set if we created the closed group v3 or got promoted to admin (and received the identity private key)
isV3: true;
name: string;
members: Array<string>;
activeAt?: number;
expireTimer?: number | null;
blocked?: boolean;
admins?: Array<string>;
weWereJustAdded?: boolean;
};
export interface GroupDiff extends MemberChanges {
newName?: string;
}
@ -230,11 +217,7 @@ function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff
return groupDiff;
}
function isV3(details: GroupInfo | GroupInfoV3): details is GroupInfoV3 {
return (details as GroupInfoV3).isV3 === true;
}
export async function updateOrCreateClosedGroup(details: GroupInfo | GroupInfoV3) {
export async function updateOrCreateClosedGroup(details: GroupInfo) {
const { id, weWereJustAdded, expireTimer } = details;
const conversation = await getConversationController().getOrCreateAndWait(
@ -245,7 +228,6 @@ export async function updateOrCreateClosedGroup(details: GroupInfo | GroupInfoV3
const updates: Pick<
ConversationAttributes,
| 'type'
// | 'identityPrivateKey'
| 'members'
| 'displayNameInProfile'
| 'is_medium_group'
@ -256,15 +238,13 @@ export async function updateOrCreateClosedGroup(details: GroupInfo | GroupInfoV3
> = {
displayNameInProfile: details.name,
members: details.members,
type: isV3(details) ? ConversationTypeEnum.GROUPV3 : ConversationTypeEnum.GROUP,
type: ConversationTypeEnum.GROUP,
is_medium_group: true,
active_at: details.activeAt ? details.activeAt : 0,
left: details.activeAt ? false : true,
lastJoinedTimestamp: details.activeAt && weWereJustAdded ? Date.now() : details.activeAt || 0,
hidden: false,
// identityPrivateKey: isV3(details) ? details.identityPrivateKey : undefined,
};
console.warn('updates', updates);
conversation.set(updates);

@ -251,7 +251,6 @@ export interface ReduxConversationType {
isBlocked?: boolean;
isHidden: boolean;
isKickedFromGroup?: boolean;
subscriberCount?: number;
left?: boolean;
avatarPath?: string | null; // absolute filepath to the avatar
groupAdmins?: Array<string>; // admins for closed groups and admins for open groups
@ -271,9 +270,6 @@ export interface ReduxConversationType {
// Should only be present on opengroups - the capabilities we have on this room.
capabilities?: Array<string>;
readCapability?: boolean;
writeCapability?: boolean;
uploadCapability?: boolean;
}
export interface NotificationForConvoOption {

@ -1,29 +0,0 @@
import * as CallDucks from './call';
import * as conversationDucks from './conversations';
import * as defaultRoomDucks from './defaultRooms';
import * as DialogsDucks from './modalDialog';
import * as OnionDucks from './onion';
import * as PrimaryColorDucks from './primaryColor';
import * as SearchDucks from './search';
import * as SectionDucks from './section';
import * as StagedAttachmentDucks from './stagedAttachments';
import * as ThemeDucks from './theme';
import * as TimerOptionsDucks from './timerOptions';
import * as UserDucks from './user';
import * as UserConfigDucks from './userConfig';
export {
CallDucks,
DialogsDucks,
OnionDucks,
PrimaryColorDucks,
SearchDucks,
SectionDucks,
StagedAttachmentDucks,
ThemeDucks,
TimerOptionsDucks,
UserConfigDucks,
UserDucks,
conversationDucks,
defaultRoomDucks,
};

@ -0,0 +1,62 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
type RoomInfo = {
canWrite: boolean;
subscriberCount: number;
};
export type SogsRoomInfoState = {
rooms: Record<string, RoomInfo>;
};
export const initialSogsRoomInfoState: SogsRoomInfoState = {
rooms: {},
};
function addEmptyEntryIfNeeded(state: any, convoId: string) {
if (!state.rooms[convoId]) {
state.rooms[convoId] = { canWrite: true, subscriberCount: 0 };
}
}
/**
* This slice is the one holding the memory-only infos of sogs room. This includes
* - writeCapability
* - subscriberCount
*/
const sogsRoomInfosSlice = createSlice({
name: 'sogsRoomInfos',
initialState: initialSogsRoomInfoState,
reducers: {
setSubscriberCount(state, action: PayloadAction<{ convoId: string; subscriberCount: number }>) {
addEmptyEntryIfNeeded(state, action.payload.convoId);
if (isFinite(action.payload.subscriberCount)) {
state.rooms[action.payload.convoId].subscriberCount = action.payload.subscriberCount;
}
return state;
},
setCanWrite(state, action: PayloadAction<{ convoId: string; canWrite: boolean }>) {
addEmptyEntryIfNeeded(state, action.payload.convoId);
state.rooms[action.payload.convoId].canWrite = !!action.payload.canWrite;
return state;
},
},
});
const { actions, reducer } = sogsRoomInfosSlice;
const { setSubscriberCount, setCanWrite } = actions;
export const ReduxSogsRoomInfos = {
setSubscriberCountOutsideRedux,
setCanWriteOutsideRedux,
sogsRoomInfoReducer: reducer,
};
function setSubscriberCountOutsideRedux(convoId: string, subscriberCount: number) {
window.inboxStore?.dispatch(setSubscriberCount({ convoId, subscriberCount }));
}
function setCanWriteOutsideRedux(convoId: string, canWrite: boolean) {
window.inboxStore?.dispatch(setCanWrite({ convoId, canWrite }));
}

@ -26,9 +26,6 @@ const userConfigSlice = createSlice({
disableRecoveryPhrasePrompt: state => {
state.showRecoveryPhrasePrompt = false;
},
toggleMessageRequests: state => {
state.hideMessageRequests = !state.hideMessageRequests;
},
showMessageRequestBanner: state => {
state.hideMessageRequests = false;
},
@ -42,8 +39,10 @@ const { actions, reducer } = userConfigSlice;
export const {
toggleAudioAutoplay,
disableRecoveryPhrasePrompt,
toggleMessageRequests,
showMessageRequestBanner,
hideMessageRequestBanner,
} = actions;
export const userConfigReducer = reducer;
export function showMessageRequestBannerOutsideRedux() {
window.inboxStore?.dispatch(actions.showMessageRequestBanner());
}

@ -7,6 +7,7 @@ import { reducer as theme } from './ducks/theme';
import { reducer as primaryColor } from './ducks/primaryColor';
import { reducer as section, SectionStateType } from './ducks/section';
import { defaultRoomReducer as defaultRooms, DefaultRoomsState } from './ducks/defaultRooms';
import { ReduxSogsRoomInfos, SogsRoomInfoState } from './ducks/sogsRoomInfo';
import { callReducer as call, CallStateType } from './ducks/call';
import { defaultOnionReducer as onionPaths, OnionState } from './ducks/onion';
@ -33,6 +34,7 @@ export type StateType = {
timerOptions: TimerOptionsState;
stagedAttachments: StagedAttachmentsStateType;
call: CallStateType;
sogsRoomInfo: SogsRoomInfoState;
};
export const reducers = {
@ -49,6 +51,7 @@ export const reducers = {
timerOptions,
stagedAttachments,
call,
sogsRoomInfo: ReduxSogsRoomInfos.sogsRoomInfoReducer,
};
// Making this work would require that our reducer signature supported AnyAction, not

@ -37,6 +37,7 @@ import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversa
import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions';
import { filter, isEmpty, pick, sortBy } from 'lodash';
import { getCanWrite, getSubscriberCount } from './sogsRoomInfo';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@ -74,22 +75,21 @@ export const getSelectedConversationIsPublic = createSelector(
}
);
export const getIsTypingEnabled = createSelector(
getConversations,
getSelectedConversationKey,
(state: ConversationsStateType, selectedConvoPubkey?: string): boolean => {
if (!selectedConvoPubkey) {
return false;
}
const selectedConvo = state.conversationLookup[selectedConvoPubkey];
if (!selectedConvo) {
return false;
}
const { isBlocked, isKickedFromGroup, left, isPublic, writeCapability } = selectedConvo;
return !(isBlocked || isKickedFromGroup || left || (isPublic && !writeCapability));
export function getIsTypingEnabled(state: StateType) {
const selectedConvoPubkey = getSelectedConversationKey(state);
if (!selectedConvoPubkey) {
return false;
}
);
const selectedConvo = state.conversations.conversationLookup[selectedConvoPubkey];
if (!selectedConvo) {
return false;
}
const canWrite = getCanWrite(state, selectedConvoPubkey);
const { isBlocked, isKickedFromGroup, left, isPublic } = selectedConvo;
return !(isBlocked || isKickedFromGroup || left || (isPublic && !canWrite));
}
/**
* Returns true if the current conversation selected is a group conversation.
* Returns false if the current conversation selected is not a group conversation, or none are selected
@ -551,23 +551,32 @@ export const getUnreadMessageCount = createSelector(getLeftPaneLists, (state): n
return state.unreadCount;
});
export const getConversationHeaderTitleProps = createSelector(getSelectedConversation, (state):
| ConversationHeaderTitleProps
| undefined => {
if (!state) {
export const getConversationHeaderTitleProps = (
state: StateType
): ConversationHeaderTitleProps | undefined => {
const convo = getSelectedConversation(state);
if (!convo) {
return undefined;
}
return {
isKickedFromGroup: !!state.isKickedFromGroup,
conversationKey: state.id,
isMe: !!state.isMe,
members: state.members || [],
isPublic: !!state.isPublic,
subscriberCount: state.subscriberCount,
isGroup: isOpenOrClosedGroup(state.type),
currentNotificationSetting: state.currentNotificationSetting,
isKickedFromGroup: !!convo.isKickedFromGroup,
conversationKey: convo.id,
isMe: !!convo.isMe,
members: convo.members || [],
isPublic: !!convo.isPublic,
isGroup: isOpenOrClosedGroup(convo.type),
currentNotificationSetting: convo.currentNotificationSetting,
};
});
};
export const getCurrentSubscriberCount = (state: StateType): number | undefined => {
const convo = getSelectedConversation(state);
if (!convo) {
return undefined;
}
return getSubscriberCount(state, convo.id);
};
/**
* Returns the formatted text for notification setting.

@ -0,0 +1,36 @@
import { isNil } from 'lodash';
import { SogsRoomInfoState } from '../ducks/sogsRoomInfo';
import { StateType } from '../reducer';
const getSogsRoomInfoState = (state: StateType): SogsRoomInfoState => state.sogsRoomInfo;
export function getCanWrite(state: StateType, selectedConvo?: string): boolean {
if (!selectedConvo) {
return false;
}
const canWrite = getSogsRoomInfoState(state).rooms[selectedConvo]?.canWrite;
// if there is no entry in the redux slice, consider it true (as this selector will be hit for non sogs convo too)
return isNil(canWrite) ? true : canWrite;
}
export function getSubscriberCount(state: StateType, selectedConvo?: string): number {
if (!selectedConvo) {
return 0;
}
const subscriberCount = getSogsRoomInfoState(state).rooms[selectedConvo]?.subscriberCount;
// if there is no entry in the redux slice, consider it 0 (as this selector will be hit for non sogs convo too)
return isNil(subscriberCount) ? 0 : subscriberCount;
}
export function getSubscriberCountOutsideRedux(convoId: string) {
const state = window.inboxStore?.getState();
return state ? getSubscriberCount(state, convoId) : 0;
}
export function getCanWriteOutsideRedux(convoId: string) {
const state = window.inboxStore?.getState();
return state ? getCanWrite(state, convoId) : false;
}

@ -1,20 +1,17 @@
import { StateType } from '../reducer';
import { UserConfigState } from '../ducks/userConfig';
import { createSelector } from '@reduxjs/toolkit';
export const getUserConfig = (state: StateType): UserConfigState => state.userConfig;
export const getAudioAutoplay = (state: StateType): boolean => state.userConfig.audioAutoplay;
export const getAudioAutoplay = createSelector(
getUserConfig,
(state: UserConfigState): boolean => state.audioAutoplay
);
export const getShowRecoveryPhrasePrompt = (state: StateType): boolean =>
state.userConfig?.showRecoveryPhrasePrompt || false;
export const getShowRecoveryPhrasePrompt = createSelector(
getUserConfig,
(state: UserConfigState): boolean => state.showRecoveryPhrasePrompt
);
export const getHideMessageRequestBanner = (state: StateType): boolean => {
// I am not too sure why, but it seems that state.userConfig is not set early enough and we try to somehow fetch this too early?
return state.userConfig?.hideMessageRequests || false;
};
export const getHideMessageRequestBanner = createSelector(
getUserConfig,
(state: UserConfigState): boolean => state.hideMessageRequests
);
export const getHideMessageRequestBannerOutsideRedux = (): boolean => {
const state = window.inboxStore?.getState();
return state ? getHideMessageRequestBanner(state) : true;
};

@ -84,21 +84,6 @@ describe('fillConvoAttributesWithDefaults', () => {
});
});
describe('subscriberCount', () => {
it('initialize subscriberCount if not given', () => {
expect(fillConvoAttributesWithDefaults({} as ConversationAttributes)).to.have.deep.property(
'subscriberCount',
0
);
});
it('do not override subscriberCount if given', () => {
expect(
fillConvoAttributesWithDefaults({ subscriberCount: 123 } as ConversationAttributes)
).to.have.deep.property('subscriberCount', 123);
});
});
describe('expireTimer', () => {
it('initialize expireTimer if not given', () => {
expect(fillConvoAttributesWithDefaults({} as ConversationAttributes)).to.have.deep.property(

@ -13,69 +13,79 @@ import { formatRowOfConversation } from '../../../../node/database_utility';
describe('formatRowOfConversation', () => {
describe('isTrustedForAttachmentDownload', () => {
it('initialize isTrustedForAttachmentDownload if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property(
expect(formatRowOfConversation({}, 'test')).to.have.deep.property(
'isTrustedForAttachmentDownload',
false
);
});
it('do not override isTrustedForAttachmentDownload if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ isTrustedForAttachmentDownload: 1 })).to.have.deep.property(
'isTrustedForAttachmentDownload',
true
);
expect(
formatRowOfConversation({ isTrustedForAttachmentDownload: 1 }, 'test')
).to.have.deep.property('isTrustedForAttachmentDownload', true);
});
it('do not override isTrustedForAttachmentDownload if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ isTrustedForAttachmentDownload: 0 })).to.have.deep.property(
'isTrustedForAttachmentDownload',
false
);
expect(
formatRowOfConversation({ isTrustedForAttachmentDownload: 0 }, 'test')
).to.have.deep.property('isTrustedForAttachmentDownload', false);
});
});
describe('isPinned', () => {
it('initialize isPinned if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('isPinned', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('isPinned', false);
});
it('do not override isPinned if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ isPinned: 1 })).to.have.deep.property('isPinned', true);
expect(formatRowOfConversation({ isPinned: 1 }, 'test')).to.have.deep.property(
'isPinned',
true
);
});
it('do not override isPinned if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ isPinned: 0 })).to.have.deep.property('isPinned', false);
expect(formatRowOfConversation({ isPinned: 0 }, 'test')).to.have.deep.property(
'isPinned',
false
);
});
});
describe('isApproved', () => {
it('initialize isApproved if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('isApproved', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('isApproved', false);
});
it('do not override isApproved if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ isApproved: 1 })).to.have.deep.property('isApproved', true);
expect(formatRowOfConversation({ isApproved: 1 }, 'test')).to.have.deep.property(
'isApproved',
true
);
});
it('do not override isApproved if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ isApproved: 0 })).to.have.deep.property('isApproved', false);
expect(formatRowOfConversation({ isApproved: 0 }, 'test')).to.have.deep.property(
'isApproved',
false
);
});
});
describe('didApproveMe', () => {
it('initialize didApproveMe if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('didApproveMe', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('didApproveMe', false);
});
it('do not override didApproveMe if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ didApproveMe: 1 })).to.have.deep.property(
expect(formatRowOfConversation({ didApproveMe: 1 }, 'test')).to.have.deep.property(
'didApproveMe',
true
);
});
it('do not override didApproveMe if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ didApproveMe: 0 })).to.have.deep.property(
expect(formatRowOfConversation({ didApproveMe: 0 }, 'test')).to.have.deep.property(
'didApproveMe',
false
);
@ -84,18 +94,18 @@ describe('formatRowOfConversation', () => {
describe('is_medium_group', () => {
it('initialize is_medium_group if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('is_medium_group', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('is_medium_group', false);
});
it('do not override is_medium_group if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ is_medium_group: 1 })).to.have.deep.property(
expect(formatRowOfConversation({ is_medium_group: 1 }, 'test')).to.have.deep.property(
'is_medium_group',
true
);
});
it('do not override is_medium_group if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ is_medium_group: 0 })).to.have.deep.property(
expect(formatRowOfConversation({ is_medium_group: 0 }, 'test')).to.have.deep.property(
'is_medium_group',
false
);
@ -104,18 +114,18 @@ describe('formatRowOfConversation', () => {
describe('mentionedUs', () => {
it('initialize mentionedUs if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('mentionedUs', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('mentionedUs', false);
});
it('do not override mentionedUs if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ mentionedUs: 1 })).to.have.deep.property(
expect(formatRowOfConversation({ mentionedUs: 1 }, 'test')).to.have.deep.property(
'mentionedUs',
true
);
});
it('do not override mentionedUs if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ mentionedUs: 0 })).to.have.deep.property(
expect(formatRowOfConversation({ mentionedUs: 0 }, 'test')).to.have.deep.property(
'mentionedUs',
false
);
@ -124,18 +134,18 @@ describe('formatRowOfConversation', () => {
describe('isKickedFromGroup', () => {
it('initialize isKickedFromGroup if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('isKickedFromGroup', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('isKickedFromGroup', false);
});
it('do not override isKickedFromGroup if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ isKickedFromGroup: 1 })).to.have.deep.property(
expect(formatRowOfConversation({ isKickedFromGroup: 1 }, 'test')).to.have.deep.property(
'isKickedFromGroup',
true
);
});
it('do not override isKickedFromGroup if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ isKickedFromGroup: 0 })).to.have.deep.property(
expect(formatRowOfConversation({ isKickedFromGroup: 0 }, 'test')).to.have.deep.property(
'isKickedFromGroup',
false
);
@ -144,28 +154,28 @@ describe('formatRowOfConversation', () => {
describe('left', () => {
it('initialize left if they are not given', () => {
expect(formatRowOfConversation({})).to.have.deep.property('left', false);
expect(formatRowOfConversation({}, 'test')).to.have.deep.property('left', false);
});
it('do not override left if they are set in the row as integer: true', () => {
expect(formatRowOfConversation({ left: 1 })).to.have.deep.property('left', true);
expect(formatRowOfConversation({ left: 1 }, 'test')).to.have.deep.property('left', true);
});
it('do not override left if they are set in the row as integer: false', () => {
expect(formatRowOfConversation({ left: 0 })).to.have.deep.property('left', false);
expect(formatRowOfConversation({ left: 0 }, 'test')).to.have.deep.property('left', false);
});
});
describe('row', () => {
it('row null returns null', () => {
expect(formatRowOfConversation(null as any)).to.be.equal(
expect(formatRowOfConversation(null as any, 'test')).to.be.equal(
null,
'formatRowOfConversation with null should return null'
);
});
it('row undefined returns null', () => {
expect(formatRowOfConversation(undefined as any)).to.be.equal(
expect(formatRowOfConversation(undefined as any, 'test')).to.be.equal(
null,
'formatRowOfConversation with undefined should return null'
);
@ -174,21 +184,21 @@ describe('formatRowOfConversation', () => {
describe('groupAdmins', () => {
it('groupAdmins undefined fills it with []', () => {
expect(formatRowOfConversation({ groupAdmins: undefined })).to.be.have.deep.property(
expect(formatRowOfConversation({ groupAdmins: undefined }, 'test')).to.be.have.deep.property(
'groupAdmins',
[]
);
});
it('groupAdmins null fills it with []', () => {
expect(formatRowOfConversation({ groupAdmins: null })).to.be.have.deep.property(
expect(formatRowOfConversation({ groupAdmins: null }, 'test')).to.be.have.deep.property(
'groupAdmins',
[]
);
});
it('groupAdmins [] fills it with []', () => {
expect(formatRowOfConversation({ groupAdmins: '[]' })).to.be.have.deep.property(
expect(formatRowOfConversation({ groupAdmins: '[]' }, 'test')).to.be.have.deep.property(
'groupAdmins',
[]
);
@ -196,86 +206,96 @@ describe('formatRowOfConversation', () => {
it('groupAdmins ["12345"] from db as string', () => {
expect(
formatRowOfConversation({ groupAdmins: '["12345"]' })
formatRowOfConversation({ groupAdmins: '["12345"]' }, 'test')
).to.be.have.deep.property('groupAdmins', ['12345']);
});
it('groupAdmins ["12345", "52345"] fills it with []', () => {
expect(
formatRowOfConversation({ groupAdmins: '["12345", "52345"]' })
formatRowOfConversation({ groupAdmins: '["12345", "52345"]' }, 'test')
).to.be.have.deep.property('groupAdmins', ['12345', '52345']);
});
});
describe('members', () => {
it('members undefined fills it with []', () => {
expect(formatRowOfConversation({ members: undefined })).to.be.have.deep.property(
expect(formatRowOfConversation({ members: undefined }, 'test')).to.be.have.deep.property(
'members',
[]
);
});
it('members null fills it with []', () => {
expect(formatRowOfConversation({ members: null })).to.be.have.deep.property('members', []);
expect(formatRowOfConversation({ members: null }, 'test')).to.be.have.deep.property(
'members',
[]
);
});
it('members [] fills it with []', () => {
expect(formatRowOfConversation({ members: '[]' })).to.be.have.deep.property('members', []);
expect(formatRowOfConversation({ members: '[]' }, 'test')).to.be.have.deep.property(
'members',
[]
);
});
it('members ["12345"] from db as string', () => {
expect(formatRowOfConversation({ members: '["12345"]' })).to.be.have.deep.property(
'members',
['12345']
);
expect(
formatRowOfConversation({ members: '["12345"]' }, 'test')
).to.be.have.deep.property('members', ['12345']);
});
it('members ["12345", "52345"] fills it with []', () => {
expect(
formatRowOfConversation({ members: '["12345", "52345"]' })
formatRowOfConversation({ members: '["12345", "52345"]' }, 'test')
).to.be.have.deep.property('members', ['12345', '52345']);
});
});
describe('zombies', () => {
it('zombies undefined fills it with []', () => {
expect(formatRowOfConversation({ zombies: undefined })).to.be.have.deep.property(
expect(formatRowOfConversation({ zombies: undefined }, 'test')).to.be.have.deep.property(
'zombies',
[]
);
});
it('zombies null fills it with []', () => {
expect(formatRowOfConversation({ zombies: null })).to.be.have.deep.property('zombies', []);
expect(formatRowOfConversation({ zombies: null }, 'test')).to.be.have.deep.property(
'zombies',
[]
);
});
it('zombies [] fills it with []', () => {
expect(formatRowOfConversation({ zombies: '[]' })).to.be.have.deep.property('zombies', []);
expect(formatRowOfConversation({ zombies: '[]' }, 'test')).to.be.have.deep.property(
'zombies',
[]
);
});
it('zombies ["12345"] from db as string', () => {
expect(formatRowOfConversation({ zombies: '["12345"]' })).to.be.have.deep.property(
'zombies',
['12345']
);
expect(
formatRowOfConversation({ zombies: '["12345"]' }, 'test')
).to.be.have.deep.property('zombies', ['12345']);
});
it('zombies ["12345", "52345"] fills it with ["12345", "52345"]', () => {
expect(
formatRowOfConversation({ zombies: '["12345", "52345"]' })
formatRowOfConversation({ zombies: '["12345", "52345"]' }, 'test')
).to.be.have.deep.property('zombies', ['12345', '52345']);
});
});
it('throws an error if a key is not expected', () => {
expect(() => formatRowOfConversation({ not_valid: undefined })).throws(
expect(() => formatRowOfConversation({ not_valid: undefined }, 'test')).throws(
'formatRowOfConversation: an invalid key was given in the record: not_valid'
);
});
it('throws an error if a key is not expected but has other valid keys', () => {
expect(() =>
formatRowOfConversation({ triggerNotificationsFor: 'all', not_valid: undefined })
formatRowOfConversation({ triggerNotificationsFor: 'all', not_valid: undefined }, 'test')
).throws('formatRowOfConversation: an invalid key was given in the record: not_valid');
});
@ -291,7 +311,8 @@ describe('formatRowOfConversation', () => {
avatarPointer: 'avatarPointer',
avatarInProfile: 'avatarInProfile',
avatarImageId: 1234,
} as ConversationAttributes)
} as ConversationAttributes),
'test'
)
).have.deep.property('displayNameInProfile', 'displayNameInProfile');
@ -306,7 +327,8 @@ describe('formatRowOfConversation', () => {
avatarPointer: 'avatarPointer',
avatarInProfile: 'avatarInProfile',
avatarImageId: 1234,
} as ConversationAttributes)
} as ConversationAttributes),
'test'
)
).have.deep.property('displayNameInProfile', 'displayNameInProfile');
});

@ -28,7 +28,6 @@ describe('state/selectors/conversations', () => {
left: false,
hasNickname: false,
isPublic: false,
subscriberCount: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
isGroup: false,
@ -58,7 +57,6 @@ describe('state/selectors/conversations', () => {
left: false,
hasNickname: false,
isPublic: false,
subscriberCount: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
isGroup: false,
@ -88,7 +86,6 @@ describe('state/selectors/conversations', () => {
left: false,
hasNickname: false,
isPublic: false,
subscriberCount: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
isGroup: false,
@ -118,7 +115,6 @@ describe('state/selectors/conversations', () => {
left: false,
hasNickname: false,
isPublic: false,
subscriberCount: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
isGroup: false,
@ -148,7 +144,6 @@ describe('state/selectors/conversations', () => {
left: false,
hasNickname: false,
isPublic: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
@ -193,7 +188,6 @@ describe('state/selectors/conversations', () => {
isBlocked: false,
isKickedFromGroup: false,
left: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
@ -224,7 +218,6 @@ describe('state/selectors/conversations', () => {
isBlocked: false,
isKickedFromGroup: false,
left: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
@ -254,7 +247,6 @@ describe('state/selectors/conversations', () => {
isBlocked: false,
isKickedFromGroup: false,
left: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
@ -285,7 +277,6 @@ describe('state/selectors/conversations', () => {
isBlocked: false,
isKickedFromGroup: false,
left: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,
@ -316,7 +307,6 @@ describe('state/selectors/conversations', () => {
isKickedFromGroup: false,
left: false,
subscriberCount: 0,
expireTimer: 0,
currentNotificationSetting: 'all',
weAreAdmin: false,

@ -179,8 +179,13 @@ async function createAccount(identityKeyPair: SessionKeyPair) {
async function registrationDone(ourPubkey: string, displayName: string) {
window?.log?.info('registration done');
// initializeLibSessionUtilWrappers needs our publicKey to be set
await Storage.put('primaryDevicePubKey', ourPubkey);
try {
await LibSessionUtil.initializeLibSessionUtilWrappers();
} catch (e) {
window.log.warn('LibSessionUtil.initializeLibSessionUtilWrappers failed with', e.message);
}
// Ensure that we always have a conversation for ourself
const conversation = await getConversationController().getOrCreateAndWait(
ourPubkey,
@ -199,11 +204,7 @@ async function registrationDone(ourPubkey: string, displayName: string) {
window.inboxStore?.dispatch(userActions.userChanged(user));
await Registration.markDone();
try {
await LibSessionUtil.initializeLibSessionUtilWrappers();
} catch (e) {
window.log.warn('LibSessionUtil.initializeLibSessionUtilWrappers failed with', e.message);
}
window?.log?.info('dispatching registration event');
trigger('registration_done');
}

Loading…
Cancel
Save