Skip to content

Commit

Permalink
user-groups: Remove deactivated users from groups
Browse files Browse the repository at this point in the history
As newly required to support Zulip Server 10+; see zulip#5899.

Fixes: zulip#5899
  • Loading branch information
chrisbobbe committed Nov 12, 2024
1 parent ad3a26f commit 54998e7
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
42 changes: 42 additions & 0 deletions src/user-groups/__tests__/userGroupsReducer-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @flow strict-local */

import deepFreeze from 'deep-freeze';
import invariant from 'invariant';

import * as eg from '../../__tests__/lib/exampleData';
import {
Expand All @@ -11,6 +12,7 @@ import {
EVENT_USER_GROUP_REMOVE_MEMBERS,
} from '../../actionConstants';
import userGroupsReducer from '../userGroupsReducer';
import eventToAction from '../../events/eventToAction';

describe('userGroupsReducer', () => {
describe('REGISTER_COMPLETE', () => {
Expand Down Expand Up @@ -192,4 +194,44 @@ describe('userGroupsReducer', () => {
).toEqual([{ ...group1, members: [user1.user_id, user4.user_id] }, group2]);
});
});

describe('realm_user op: update', () => {
test('a user is deactivated', () => {
const user1 = eg.makeUser();
const user2 = eg.makeUser();
const user3 = eg.makeUser();

const group1 = eg.makeUserGroup({ members: [user1.user_id, user2.user_id, user3.user_id] });
const group2 = eg.makeUserGroup({ members: [user2.user_id, user1.user_id] });
const group3 = eg.makeUserGroup({ members: [user1.user_id] });

const event = {
id: 0,
type: 'realm_user',
op: 'update',
person: { user_id: user1.user_id, is_active: false },
};

const prevUserGroupsState = deepFreeze([group1, group2, group3]);
const prevPerAccountState = eg.reduxStatePlus({
users: [user1, user2, user3],
userGroups: prevUserGroupsState,
});
const action = eventToAction(prevPerAccountState, event);

expect(action).not.toBeNull();
invariant(action != null, 'action not null');

const actualState = userGroupsReducer(prevUserGroupsState, action);

expect(actualState).toEqual([
{ ...group1, members: [user2.user_id, user3.user_id] },
{ ...group2, members: [user2.user_id] },

// A newly-empty group is not pruned; when a group is deactivated,
// we expect a user_group/remove event.
{ ...group3, members: [] },
]);
});
});
});
28 changes: 28 additions & 0 deletions src/user-groups/userGroupsReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import type { UserGroupsState, PerAccountApplicableAction } from '../types';
import {
REGISTER_COMPLETE,
EVENT,
EVENT_USER_GROUP_ADD,
EVENT_USER_GROUP_REMOVE,
EVENT_USER_GROUP_UPDATE,
EVENT_USER_GROUP_ADD_MEMBERS,
EVENT_USER_GROUP_REMOVE_MEMBERS,
RESET_ACCOUNT_DATA,
} from '../actionConstants';
import { EventTypes } from '../api/eventTypes';
import { NULL_ARRAY } from '../nullObjects';

const initialState: UserGroupsState = NULL_ARRAY;
Expand Down Expand Up @@ -69,6 +71,32 @@ export default (
case EVENT_USER_GROUP_REMOVE_MEMBERS:
return eventUserGroupRemoveMembers(state, action);

case EVENT: {
const { event } = action;
switch (event.type) {
case EventTypes.realm_user: {
switch (event.op) {
case 'update': {
const { person } = event;
// TODO(flow) teach Flow that the `person.existingUser != null` is redundant
if (person.is_active === false && person.existingUser != null) {
const userId = person.existingUser.user_id;
return state.map(g => ({ ...g, members: g.members.filter(m => m !== userId) }));
}

return state;
}

default:
return state;
}
}

default:
return state;
}
}

default:
return state;
}
Expand Down

0 comments on commit 54998e7

Please sign in to comment.