From 456d52ab1a30193103f8d13920cbe17b41afbe6a Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 8 Nov 2022 11:39:22 +1100 Subject: [PATCH] fix: make sure we do not use "group" or "private" without the enum --- .../message/message-content/MessageAvatar.tsx | 4 ++- .../message/message-content/MessageText.tsx | 3 ++- .../message-item/GenericReadableMessage.tsx | 3 ++- ts/models/conversationAttributes.ts | 25 +++++++++++++++++-- ts/node/sql.ts | 4 +-- .../conversations/ConversationController.ts | 8 ++++-- ts/session/group/closed-group.ts | 2 +- ts/state/selectors/conversations.ts | 17 ++++++++----- .../models/formatRowOfConversation_test.ts | 3 ++- 9 files changed, 52 insertions(+), 17 deletions(-) diff --git a/ts/components/conversation/message/message-content/MessageAvatar.tsx b/ts/components/conversation/message/message-content/MessageAvatar.tsx index a2b1a878d..50dea668e 100644 --- a/ts/components/conversation/message/message-content/MessageAvatar.tsx +++ b/ts/components/conversation/message/message-content/MessageAvatar.tsx @@ -1,6 +1,7 @@ import React, { useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { OpenGroupData } from '../../../../data/opengroups'; +import { ConversationTypeEnum } from '../../../../models/conversationAttributes'; import { MessageRenderingProps } from '../../../../models/messageType'; import { findCachedBlindedMatchOrLookItUp } from '../../../../session/apis/open_group_api/sogsv3/knownBlindedkeys'; import { getConversationController } from '../../../../session/conversations'; @@ -55,7 +56,8 @@ export const MessageAvatar = (props: Props) => { isPublic, } = avatarProps; - if (conversationType !== 'group' || direction === 'outgoing') { + // no avatar when this is not a private conversation + if (conversationType === ConversationTypeEnum.PRIVATE || direction === 'outgoing') { return null; } const userName = authorName || authorProfileName || sender; diff --git a/ts/components/conversation/message/message-content/MessageText.tsx b/ts/components/conversation/message/message-content/MessageText.tsx index 5a697cc28..d84d1bfac 100644 --- a/ts/components/conversation/message/message-content/MessageText.tsx +++ b/ts/components/conversation/message/message-content/MessageText.tsx @@ -1,6 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import { useSelector } from 'react-redux'; +import { isOpenOrClosedGroup } from '../../../../models/conversationAttributes'; import { MessageRenderingProps } from '../../../../models/messageType'; import { getMessageTextProps, @@ -44,7 +45,7 @@ export const MessageText = (props: Props) => { text={contents || ''} disableLinks={multiSelectMode} disableJumbomoji={false} - isGroup={conversationType === 'group'} + isGroup={isOpenOrClosedGroup(conversationType)} /> ); diff --git a/ts/components/conversation/message/message-item/GenericReadableMessage.tsx b/ts/components/conversation/message/message-item/GenericReadableMessage.tsx index 1f49a35ae..92ef3a2db 100644 --- a/ts/components/conversation/message/message-item/GenericReadableMessage.tsx +++ b/ts/components/conversation/message/message-item/GenericReadableMessage.tsx @@ -20,6 +20,7 @@ import { MessageAvatar } from '../message-content/MessageAvatar'; import { MessageContentWithStatuses } from '../message-content/MessageContentWithStatus'; import { ReadableMessage } from './ReadableMessage'; import styled, { keyframes } from 'styled-components'; +import { isOpenOrClosedGroup } from '../../../../models/conversationAttributes'; export type GenericReadableMessageSelectorProps = Pick< MessageRenderingProps, @@ -221,7 +222,7 @@ export const GenericReadableMessage = (props: Props) => { } const selected = isMessageSelected || false; - const isGroup = conversationType === 'group'; + const isGroup = isOpenOrClosedGroup(conversationType); const isIncoming = direction === 'incoming'; return ( diff --git a/ts/models/conversationAttributes.ts b/ts/models/conversationAttributes.ts index c701180db..83938d2a0 100644 --- a/ts/models/conversationAttributes.ts +++ b/ts/models/conversationAttributes.ts @@ -1,12 +1,33 @@ import { defaults } from 'lodash'; import { LastMessageStatusType } from '../state/ducks/conversations'; +/** + * Private chats have always the type `Private` + * Open groups have always the type `Group` + * Closed group have the type `Group` when they are not v3 and the type `CLOSED_GROUP` when they v3. + * To identity between an open or closed group before v3, we need to rely on the prefix (05 is closed groups, publicChat is opengroup) + * + * + * We will need to support existing closed groups foir now, but we will be able to get rid of existing closed groups at some point. + * When we do get rid of them, we will be able to remove any GROUP conversation with prefix 05 (as they are old closed groups) and update the remaining GROUP to be opengroups instead + */ export enum ConversationTypeEnum { GROUP = 'group', - CLOSED_GROUP = 'groupv3', + GROUPV3 = 'groupv3', PRIVATE = 'private', } +export function isOpenOrClosedGroup(conversationType: ConversationTypeEnum) { + return ( + conversationType === ConversationTypeEnum.GROUP || + conversationType === ConversationTypeEnum.GROUPV3 + ); +} + +export function isDirectConversation(conversationType: ConversationTypeEnum) { + return conversationType === ConversationTypeEnum.PRIVATE; +} + /** * all: all notifications enabled, the default * disabled: no notifications at all @@ -17,7 +38,7 @@ export type ConversationNotificationSettingType = typeof ConversationNotificatio export interface ConversationAttributes { id: string; - type: string; + type: ConversationTypeEnum.PRIVATE | ConversationTypeEnum.GROUPV3 | ConversationTypeEnum.GROUP; // 0 means inactive (undefined and null too but we try to get rid of them and only have 0 = inactive) active_at: number; diff --git a/ts/node/sql.ts b/ts/node/sql.ts index c4ca98047..ed8bb3d0a 100644 --- a/ts/node/sql.ts +++ b/ts/node/sql.ts @@ -22,7 +22,7 @@ import { redactAll } from '../util/privacy'; // checked - only node import { LocaleMessagesType } from './locale'; // checked - only node import { PubKey } from '../session/types/PubKey'; // checked - only node import { StorageItem } from './storage_item'; // checked - only node -import { ConversationAttributes } from '../models/conversationAttributes'; +import { ConversationAttributes, ConversationTypeEnum } from '../models/conversationAttributes'; import { arrayStrToJson, assertValidConversationAttributes, @@ -2333,7 +2333,7 @@ function fillWithTestData(numConvosToAdd: number, numMsgsToAdd: number) { members: [], displayNameInProfile: `${activeAt}`, id: `05${id}`, - type: 'group', + type: ConversationTypeEnum.GROUPV3, didApproveMe: false, expireTimer: 0, groupAdmins: [], diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts index 4b2a15533..96354418d 100644 --- a/ts/session/conversations/ConversationController.ts +++ b/ts/session/conversations/ConversationController.ts @@ -65,8 +65,12 @@ export class ConversationController { throw new TypeError("'id' must be a string"); } - if (type !== ConversationTypeEnum.PRIVATE && type !== ConversationTypeEnum.GROUP) { - throw new TypeError(`'type' must be 'private' or 'group' got: '${type}'`); + if ( + type !== ConversationTypeEnum.PRIVATE && + type !== ConversationTypeEnum.GROUP && + type !== ConversationTypeEnum.GROUPV3 + ) { + throw new TypeError(`'type' must be 'private' or 'group' or 'groupv3' but got: '${type}'`); } if (!this._initialFetchComplete) { diff --git a/ts/session/group/closed-group.ts b/ts/session/group/closed-group.ts index 71be70041..242ceb064 100644 --- a/ts/session/group/closed-group.ts +++ b/ts/session/group/closed-group.ts @@ -253,7 +253,7 @@ export async function updateOrCreateClosedGroup(details: GroupInfo | GroupInfoV3 > = { displayNameInProfile: details.name, members: details.members, - type: 'group', + type: isV3(details) ? ConversationTypeEnum.GROUPV3 : ConversationTypeEnum.GROUP, is_medium_group: true, active_at: details.activeAt ? details.activeAt : 0, left: details.activeAt ? false : true, diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 563db45f8..2b8930474 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -33,7 +33,7 @@ import { LightBoxOptions } from '../../components/conversation/SessionConversati import { getConversationController } from '../../session/conversations'; import { UserUtils } from '../../session/utils'; import { Storage } from '../../util/storage'; -import { ConversationTypeEnum } from '../../models/conversationAttributes'; +import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes'; import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions'; import { filter, isEmpty, pick, sortBy } from 'lodash'; @@ -97,7 +97,8 @@ export const getIsTypingEnabled = createSelector( export const getSelectedConversationIsGroup = createSelector( getSelectedConversation, (state: ReduxConversationType | undefined): boolean => { - return state?.type === 'group' || false; + const type = state?.type; + return type ? isOpenOrClosedGroup(type) : false; } ); @@ -107,7 +108,11 @@ export const getSelectedConversationIsGroup = createSelector( export const isClosedGroupConversation = createSelector( getSelectedConversation, (state: ReduxConversationType | undefined): boolean => { - return (state?.type === 'group' && !state.isPublic) || false; + return ( + (state?.type === ConversationTypeEnum.GROUP && !state.isPublic) || + state?.type === ConversationTypeEnum.GROUPV3 || + false + ); } ); @@ -117,7 +122,7 @@ export const isClosedGroupConversation = createSelector( export const isPublicGroupConversation = createSelector( getSelectedConversation, (state: ReduxConversationType | undefined): boolean => { - return (state?.type === 'group' && state.isPublic) || false; + return (state?.type === ConversationTypeEnum.GROUP && state.isPublic) || false; } ); @@ -293,7 +298,7 @@ function getConversationTitle( return conversation.displayNameInProfile; } - if (conversation.type === 'group') { + if (isOpenOrClosedGroup(conversation.type)) { return (testingi18n || window.i18n)('unknown'); } return conversation.id; @@ -560,7 +565,7 @@ export const getConversationHeaderTitleProps = createSelector(getSelectedConvers members: state.members || [], isPublic: !!state.isPublic, subscriberCount: state.subscriberCount, - isGroup: state.type === 'group', + isGroup: isOpenOrClosedGroup(state.type), currentNotificationSetting: state.currentNotificationSetting, }; }); diff --git a/ts/test/session/unit/models/formatRowOfConversation_test.ts b/ts/test/session/unit/models/formatRowOfConversation_test.ts index 137c7249d..73162688b 100644 --- a/ts/test/session/unit/models/formatRowOfConversation_test.ts +++ b/ts/test/session/unit/models/formatRowOfConversation_test.ts @@ -4,6 +4,7 @@ import { expect } from 'chai'; import { describe } from 'mocha'; import { ConversationAttributes, + ConversationTypeEnum, fillConvoAttributesWithDefaults, } from '../../../../models/conversationAttributes'; import { formatRowOfConversation } from '../../../../node/database_utility'; @@ -283,7 +284,7 @@ describe('formatRowOfConversation', () => { formatRowOfConversation( fillConvoAttributesWithDefaults({ id: '123456', - type: 'group', + type: ConversationTypeEnum.GROUP, nickname: 'nickname', displayNameInProfile: 'displayNameInProfile', profileKey: '',