[MM-63504] When changing a channel to group synced, it doesn't always clear members (#30526)

* fix issue with channel and team membership after group constraints are enabled
Этот коммит содержится в:
Ben Cooke
2025-04-01 12:20:00 -04:00
коммит произвёл GitHub
родитель a47269cfe2
Коммит 2454de5b4a
10 изменённых файлов: 614 добавлений и 91 удалений

Просмотреть файл

@@ -424,27 +424,9 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
return;
}
const promises = [];
let privacyChangePromise;
if (isPrivacyChanging) {
const convert = actions.updateChannelPrivacy(channel.id, isPublic ? Constants.OPEN_CHANNEL : Constants.PRIVATE_CHANNEL);
promises.push(
convert.then((res: ActionResult) => {
if ('error' in res) {
return res;
}
return actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
});
}),
);
} else {
promises.push(
actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
}),
);
privacyChangePromise = actions.updateChannelPrivacy(channel.id, isPublic ? Constants.OPEN_CHANNEL : Constants.PRIVATE_CHANNEL);
}
const patchChannelSyncable = groups.
@@ -453,57 +435,80 @@ export default class ChannelDetails extends React.PureComponent<ChannelDetailsPr
}).
map((g) => actions.patchGroupSyncable(g.id, channelID, SyncableType.Channel, {scheme_admin: g.scheme_admin}));
const unlink = origGroups.
filter((g) => {
return !groups.some((group) => group.id === g.id);
}).
map((g) => actions.unlinkGroupSyncable(g.id, channelID, SyncableType.Channel));
const link = groups.
filter((g) => {
return !origGroups.some((group) => group.id === g.id);
}).
map((g) => actions.linkGroupSyncable(g.id, channelID, SyncableType.Channel, {auto_add: true, scheme_admin: g.scheme_admin}));
const groupActions = [...promises, ...patchChannelSyncable, ...unlink, ...link];
if (groupActions.length > 0) {
const result = await Promise.all(groupActions);
const resultWithError = result.find((r) => 'error' in r);
// First execute link operations
const promisesToExecute = [...patchChannelSyncable, ...link];
if (privacyChangePromise) {
promisesToExecute.push(privacyChangePromise);
}
const linkResult = await Promise.all(promisesToExecute);
let resultWithError = linkResult.find((r) => 'error' in r);
if (resultWithError && 'error' in resultWithError) {
serverError = <FormError error={resultWithError.error.message}/>;
}
// Then patch the channel
const patchResult = await actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
});
if ('error' in patchResult) {
serverError = <FormError error={patchResult.error.message}/>;
}
const unlink = origGroups.
filter((g) => {
return !groups.some((group) => group.id === g.id);
}).
map((g) => actions.unlinkGroupSyncable(g.id, channelID, SyncableType.Channel));
// Finally execute unlink operations
if (unlink.length > 0) {
const unlinkResult = await Promise.all(unlink);
resultWithError = unlinkResult.find((r) => 'error' in r);
if (resultWithError && 'error' in resultWithError) {
serverError = <FormError error={resultWithError.error.message}/>;
} else {
if (unlink.length > 0) {
trackEvent('admin_channel_config_page', 'groups_removed_from_channel', {count: unlink.length, channel_id: channelID});
}
if (link.length > 0) {
trackEvent('admin_channel_config_page', 'groups_added_to_channel', {count: link.length, channel_id: channelID});
}
const actionsToAwait: any[] = [];
if (this.props.channelModerationEnabled) {
actionsToAwait.push(actions.getGroups(channelID));
}
if (isPrivacyChanging) {
// If the privacy is changing update the manage_members value for the channel moderation widget
if (this.props.channelModerationEnabled) {
actionsToAwait.push(
actions.getChannelModerations(channelID).then(() => {
const manageMembersIndex = channelPermissions.findIndex((element) => element.name === Permissions.CHANNEL_MODERATED_PERMISSIONS.MANAGE_MEMBERS);
if (channelPermissions) {
const updatedManageMembers = this.props.channelPermissions.find((element) => element.name === Permissions.CHANNEL_MODERATED_PERMISSIONS.MANAGE_MEMBERS);
channelPermissions[manageMembersIndex] = updatedManageMembers || channelPermissions[manageMembersIndex];
}
this.setState({channelPermissions});
}),
);
}
}
if (actionsToAwait.length > 0) {
await Promise.all(actionsToAwait);
}
await Promise.resolve();
}
}
if (!(resultWithError && 'error' in resultWithError) && !('error' in patchResult)) {
if (unlink.length > 0) {
trackEvent('admin_channel_config_page', 'groups_removed_from_channel', {count: unlink.length, channel_id: channelID});
}
if (link.length > 0) {
trackEvent('admin_channel_config_page', 'groups_added_to_channel', {count: link.length, channel_id: channelID});
}
const actionsToAwait: any[] = [];
if (this.props.channelModerationEnabled) {
actionsToAwait.push(actions.getGroups(channelID));
}
if (isPrivacyChanging) {
// If the privacy is changing update the manage_members value for the channel moderation widget
if (this.props.channelModerationEnabled) {
actionsToAwait.push(
actions.getChannelModerations(channelID).then(() => {
const manageMembersIndex = channelPermissions.findIndex((element) => element.name === Permissions.CHANNEL_MODERATED_PERMISSIONS.MANAGE_MEMBERS);
if (channelPermissions) {
const updatedManageMembers = this.props.channelPermissions.find((element) => element.name === Permissions.CHANNEL_MODERATED_PERMISSIONS.MANAGE_MEMBERS);
channelPermissions[manageMembersIndex] = updatedManageMembers || channelPermissions[manageMembersIndex];
}
this.setState({channelPermissions});
}),
);
}
}
if (actionsToAwait.length > 0) {
await Promise.all(actionsToAwait);
}
await Promise.resolve();
}
if (this.props.channelModerationEnabled) {
const patchChannelPermissionsArray: ChannelModerationPatch[] = channelPermissions.map((p) => {
return {

Просмотреть файл

@@ -180,32 +180,55 @@ export default class TeamDetails extends React.PureComponent<Props, State> {
serverError = <NeedGroupsError/>;
saveNeeded = true;
} else {
const patchTeamPromise = actions.patchTeam({
...team,
group_constrained: syncChecked,
allowed_domains: allowedDomainsChecked ? allowedDomains : '',
allow_open_invite: allAllowedChecked,
});
const patchTeamSyncable = groups.
filter((g) => {
return origGroups.some((group) => group.id === g.id && group.scheme_admin !== g.scheme_admin);
}).
map((g) => actions.patchGroupSyncable(g.id, teamID, SyncableType.Team, {scheme_admin: g.scheme_admin}));
const unlink = origGroups.
filter((g) => {
return !groups.some((group) => group.id === g.id);
}).
map((g) => actions.unlinkGroupSyncable(g.id, teamID, SyncableType.Team));
const link = groups.
filter((g) => {
return !origGroups.some((group) => group.id === g.id);
}).
map((g) => actions.linkGroupSyncable(g.id, teamID, SyncableType.Team, {auto_add: true, scheme_admin: g.scheme_admin}));
const result = await Promise.all([patchTeamPromise, ...patchTeamSyncable, ...unlink, ...link]);
const resultWithError = result.find((r) => r.error);
if (resultWithError) {
serverError = <FormError error={resultWithError.error?.message}/>;
} else {
// First execute patch and link operations
const groupResult = await Promise.all([...patchTeamSyncable, ...link]);
const groupResultWithError = groupResult.find((r) => r.error);
if (groupResultWithError) {
serverError = <FormError error={groupResultWithError.error?.message}/>;
}
// After group operations succeed, patch the team
const patchTeamResult = await actions.patchTeam({
...team,
group_constrained: syncChecked,
allowed_domains: allowedDomainsChecked ? allowedDomains : '',
allow_open_invite: allAllowedChecked,
});
if (patchTeamResult.error) {
serverError = <FormError error={patchTeamResult.error?.message}/>;
}
// After patching the team, handle unlinking groups
const unlink = origGroups.
filter((g) => {
return !groups.some((group) => group.id === g.id);
}).
map((g) => actions.unlinkGroupSyncable(g.id, teamID, SyncableType.Team));
let unlinkResultWithError: ActionResult | undefined;
if (unlink.length > 0) {
const unlinkResult = await Promise.all(unlink);
unlinkResultWithError = unlinkResult.find((r) => r.error);
if (unlinkResultWithError) {
serverError = <FormError error={unlinkResultWithError.error?.message}/>;
}
}
if (!patchTeamResult.error && !groupResultWithError && !unlinkResultWithError) {
if (unlink.length > 0) {
trackEvent('admin_team_config_page', 'groups_removed_from_team', {count: unlink.length, team_id: teamID});
}