From 64eab5160d21f74dce0caebddd6a60a03d28c521 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 5 May 2021 18:14:59 +1000 Subject: [PATCH] remove zombies from the UI only --- _locales/en/messages.json | 4 ++ ts/components/basic/Text.tsx | 9 ++- .../conversation/InviteContactsDialog.tsx | 7 +- .../conversation/UpdateGroupMembersDialog.tsx | 68 +++++++++---------- ts/receiver/closedGroups.ts | 9 +-- ts/session/group/index.ts | 14 ++-- 6 files changed, 59 insertions(+), 52 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7e99cf744..7560ea080 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -2056,6 +2056,10 @@ "message": "Anonymous", "description": "The name of currently unidentified users" }, + "removeResidueMembers": { + "message": "Clicking ok will also remove those members as they left the group.", + "description": "Shown when the admin shows the group member dialog, to warn him that zombies members will be removed" + }, "enterDisplayName": { "message": "Enter a display name", "androidKey": "activity_display_name_edit_text_hint" diff --git a/ts/components/basic/Text.tsx b/ts/components/basic/Text.tsx index 3b961627a..d1a0904b0 100644 --- a/ts/components/basic/Text.tsx +++ b/ts/components/basic/Text.tsx @@ -1,14 +1,21 @@ import React from 'react'; -import styled from 'styled-components'; +import styled, { DefaultTheme } from 'styled-components'; type TextProps = { text: string; subtle?: boolean; opposite?: boolean; + maxWidth?: string; + padding?: string; + textAlign?: 'center'; + theme?: DefaultTheme; }; const StyledDefaultText = styled.div` transition: ${props => props.theme.common.animations.defaultDuration}; + max-width: ${props => (props.maxWidth ? props.maxWidth : '')}; + padding: ${props => (props.padding ? props.padding : '')}; + text-align: ${props => (props.textAlign ? props.textAlign : '')}; font-family: ${props => props.theme.common.fonts.sessionFontDefault}; color: ${props => props.opposite diff --git a/ts/components/conversation/InviteContactsDialog.tsx b/ts/components/conversation/InviteContactsDialog.tsx index 228fa7902..18c3dc678 100644 --- a/ts/components/conversation/InviteContactsDialog.tsx +++ b/ts/components/conversation/InviteContactsDialog.tsx @@ -143,11 +143,16 @@ class InviteContactsDialogInner extends React.Component { existingMembers = []; } existingMembers = _.compact(existingMembers); + const existingZombies = convo.get('zombies') || []; const newMembers = pubkeys.filter(d => !existingMembers.includes(d)); if (newMembers.length > 0) { // Do not trigger an update if there is too many members - if (newMembers.length + existingMembers.length > window.CONSTANTS.CLOSED_GROUP_SIZE_LIMIT) { + // be sure to include current zombies in this count + if ( + newMembers.length + existingMembers.length + existingZombies.length > + window.CONSTANTS.CLOSED_GROUP_SIZE_LIMIT + ) { ToastUtils.pushTooManyMembers(); return; } diff --git a/ts/components/conversation/UpdateGroupMembersDialog.tsx b/ts/components/conversation/UpdateGroupMembersDialog.tsx index 14ac5ae31..f6873e6fc 100644 --- a/ts/components/conversation/UpdateGroupMembersDialog.tsx +++ b/ts/components/conversation/UpdateGroupMembersDialog.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { SessionModal } from '../session/SessionModal'; -import { SessionButton, SessionButtonColor } from '../session/SessionButton'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../session/SessionButton'; import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem'; import { DefaultTheme } from 'styled-components'; import { ToastUtils } from '../../session/utils'; @@ -11,6 +11,7 @@ import autoBind from 'auto-bind'; import { ConversationController } from '../../session/conversations'; import _ from 'lodash'; +import { Text } from '../basic/Text'; interface Props { titleText: string; @@ -25,8 +26,8 @@ interface Props { admins: Array; // used for closed group i18n: LocalizerType; - onSubmit: any; - onClose: any; + onSubmit: (membersLeft: Array) => void; + onClose: () => void; theme: DefaultTheme; } @@ -106,7 +107,7 @@ export class UpdateGroupMembersDialog extends React.Component { } public render() { - const { okText, cancelText, isAdmin, contactList, titleText } = this.props; + const { okText, cancelText, isAdmin, contactList, titleText, existingZombies } = this.props; const showNoMembersMessage = contactList.length === 0; @@ -116,6 +117,8 @@ export class UpdateGroupMembersDialog extends React.Component { this.state.errorDisplayed ? 'error-shown' : 'error-faded' ); + const hasZombies = Boolean(existingZombies.length); + return ( { } private renderZombiesList() { - return this.state.zombies.map((member: ContactType, index: number) => { - const isSelected = this.props.isAdmin && !member.checkmarked; + const { isAdmin } = this.props; + const { zombies } = this.state; + + if (!zombies.length) { + return <>; + } + + const zombieElements = zombies.map((member: ContactType, index: number) => { + const isSelected = isAdmin && !member.checkmarked; return ( { /> ); }); + return ( + <> +
+ {isAdmin && ( + + )} + {zombieElements} + + ); } private onKeyUp(event: any) { @@ -252,39 +278,11 @@ export class UpdateGroupMembersDialog extends React.Component { } private onZombieClicked(selected: ContactType) { - const { isAdmin, admins } = this.props; - const { zombies } = this.state; + const { isAdmin } = this.props; if (!isAdmin) { ToastUtils.pushOnlyAdminCanRemove(); return; } - if (selected.existingMember && !isAdmin) { - window.log.warn('Only group admin can remove members!'); - return; - } - - if (selected.existingMember && admins.includes(selected.id)) { - window.log.warn( - `User ${selected.id} cannot be removed as they are the creator of the closed group.` - ); - ToastUtils.pushCannotRemoveCreatorFromGroup(); - return; - } - - const updatedZombies = zombies.map(zombie => { - if (zombie.id === selected.id) { - return { ...zombie, checkmarked: !zombie.checkmarked }; - } else { - return zombie; - } - }); - - this.setState(state => { - return { - ...state, - zombies: updatedZombies, - }; - }); } } diff --git a/ts/receiver/closedGroups.ts b/ts/receiver/closedGroups.ts index 4192bb68d..23dde05a4 100644 --- a/ts/receiver/closedGroups.ts +++ b/ts/receiver/closedGroups.ts @@ -752,18 +752,11 @@ async function handleClosedGroupMemberLeft(envelope: EnvelopePlus, convo: Conver await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); convo.updateLastMessage(); // if a user just left and we are the admin, we remove him right away for everyone by sending a MEMBERS_REMOVED message so no need to add him as a zombie - if (!isCurrentUserAdmin && oldMembers.includes(sender)) { + if (oldMembers.includes(sender)) { addMemberToZombies(envelope, PubKey.cast(sender), convo); } convo.set('members', newMembers); - // if we are the admin, and there are still some members after the member left, we send a new keypair - // to the remaining members. - // also if we are the admin, we can tell to everyone that this user is effectively removed - if (isCurrentUserAdmin && !!newMembers.length) { - await ClosedGroup.sendRemovedMembers(convo, [sender], newMembers); - } - await convo.commit(); await removeFromCache(envelope); diff --git a/ts/session/group/index.ts b/ts/session/group/index.ts index 5ad56ab1c..89e522710 100644 --- a/ts/session/group/index.ts +++ b/ts/session/group/index.ts @@ -81,8 +81,6 @@ export async function getGroupSecretKey(groupId: string): Promise { return new Uint8Array(fromHex(secretKey)); } -// tslint:disable: max-func-body-length -// tslint:disable: cyclomatic-complexity export async function initiateGroupUpdate( groupId: string, groupName: string, @@ -109,7 +107,6 @@ export async function initiateGroupUpdate( throw new Error('Legacy group are not supported anymore.'); } const oldZombies = convo.get('zombies'); - console.warn('initiategroupUpdate old zombies:', oldZombies); // do not give an admins field here. We don't want to be able to update admins and // updateOrCreateClosedGroup() will update them if given the choice. @@ -123,7 +120,6 @@ export async function initiateGroupUpdate( expireTimer: convo.get('expireTimer'), avatar, }; - console.warn('initiategroupUpdate new zombies:', groupDetails.zombies); const diff = buildGroupDiff(convo, groupDetails); @@ -207,7 +203,7 @@ export async function addUpdateMessage( return message; } -export function buildGroupDiff(convo: ConversationModel, update: UpdatableGroupState): GroupDiff { +function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff { const groupDiff: GroupDiff = {}; if (convo.get('name') !== update.name) { @@ -215,13 +211,17 @@ export function buildGroupDiff(convo: ConversationModel, update: UpdatableGroupS } const oldMembers = convo.get('members'); + const oldZombies = convo.get('zombies'); + const oldMembersWithZombies = _.uniq(oldMembers.concat(oldZombies)); + + const newMembersWithZombiesLeft = _.uniq(update.members.concat(update.zombies || [])); - const addedMembers = _.difference(update.members, oldMembers); + const addedMembers = _.difference(newMembersWithZombiesLeft, oldMembersWithZombies); if (addedMembers.length > 0) { groupDiff.joiningMembers = addedMembers; } // Check if anyone got kicked: - const removedMembers = _.difference(oldMembers, update.members); + const removedMembers = _.difference(oldMembersWithZombies, newMembersWithZombiesLeft); if (removedMembers.length > 0) { groupDiff.leavingMembers = removedMembers; }