Use correct API to suspend/unsuspend user (#607)

* Use correct API to suspend/unsuspend user

* bring back suspend toggle

* make linter happy
This commit is contained in:
Borislav Pantaleev 2025-06-06 23:49:47 +03:00 committed by GitHub
parent 5165625cd0
commit ab247891dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 47 additions and 21 deletions

View File

@ -40,7 +40,7 @@ const UserAccountData = () => {
<> <>
<Stack direction="column" spacing={2} width="100%"> <Stack direction="column" spacing={2} width="100%">
<Typography variant="h6">{translate("resources.users.account_data.title")}</Typography> <Typography variant="h6">{translate("resources.users.account_data.title")}</Typography>
<Typography variant="body1"> <Typography variant="body1" component="div">
<Box> <Box>
<Accordion> <Accordion>
<AccordionSummary expandIcon={<ArrowDownwardIcon />}> <AccordionSummary expandIcon={<ArrowDownwardIcon />}>

View File

@ -33,7 +33,6 @@ const RateLimitRow = ({
}} }}
> >
<TextField <TextField
id="outlined-number"
type="number" type="number"
value={value} value={value}
onChange={handleChange} onChange={handleChange}

View File

@ -185,7 +185,6 @@ const LoginPage = () => {
} }
}; };
const UserData = ({ formData }) => { const UserData = ({ formData }) => {
const form = useFormContext(); const form = useFormContext();
@ -197,17 +196,17 @@ const LoginPage = () => {
const domain = splitMxid(formData.username)?.domain; const domain = splitMxid(formData.username)?.domain;
if (domain) { if (domain) {
const url = await getWellKnownUrl(domain); const url = await getWellKnownUrl(domain);
if (allowAnyBaseUrl || (allowMultipleBaseUrls && restrictBaseUrl.includes(url))) { if (allowAnyBaseUrl || (allowMultipleBaseUrls && restrictBaseUrl.includes(url))) {
form.setValue("base_url", url, { form.setValue("base_url", url, {
shouldValidate: true, shouldValidate: true,
shouldDirty: true, shouldDirty: true,
}); });
checkServerInfo(url); checkServerInfo(url);
} }
} }
}; };
const handleBaseUrlBlurOrChange = (event) => { const handleBaseUrlBlurOrChange = event => {
// Get the value either from the event (onChange) or from formData (onBlur) // Get the value either from the event (onChange) or from formData (onBlur)
const value = event?.target?.value || formData.base_url; const value = event?.target?.value || formData.base_url;
@ -318,16 +317,17 @@ const LoginPage = () => {
choices={baseUrlChoices} choices={baseUrlChoices}
/> />
)} )}
{!allowMultipleBaseUrls && (<TextInput {!allowMultipleBaseUrls && (
source="base_url" <TextInput
label="synapseadmin.auth.base_url" source="base_url"
autoComplete="url" label="synapseadmin.auth.base_url"
{...(loading ? { disabled: true } : {})} autoComplete="url"
readOnly={allowSingleBaseUrl} {...(loading ? { disabled: true } : {})}
resettable={allowAnyBaseUrl} readOnly={allowSingleBaseUrl}
validate={[required(), validateBaseUrl]} resettable={allowAnyBaseUrl}
onBlur={handleBaseUrlBlurOrChange} validate={[required(), validateBaseUrl]}
/> onBlur={handleBaseUrlBlurOrChange}
/>
)} )}
</Box> </Box>
<Typography className="serverVersion">{serverVersion}</Typography> <Typography className="serverVersion">{serverVersion}</Typography>

View File

@ -115,7 +115,8 @@ const userFilters = [
<BooleanInput source="guests" alwaysOn />, <BooleanInput source="guests" alwaysOn />,
<BooleanInput label="resources.users.fields.show_deactivated" source="deactivated" alwaysOn />, <BooleanInput label="resources.users.fields.show_deactivated" source="deactivated" alwaysOn />,
<BooleanInput label="resources.users.fields.show_locked" source="locked" alwaysOn />, <BooleanInput label="resources.users.fields.show_locked" source="locked" alwaysOn />,
<BooleanInput label="resources.users.fields.show_suspended" source="suspended" alwaysOn />, // waiting for https://github.com/element-hq/synapse/issues/18016
// <BooleanInput label="resources.users.fields.show_suspended" source="suspended" alwaysOn />,
]; ];
const UserPreventSelfDelete: React.FC<{ const UserPreventSelfDelete: React.FC<{
@ -208,7 +209,6 @@ export const UserList = (props: ListProps) => (
<BooleanField source="admin" label="resources.users.fields.admin" /> <BooleanField source="admin" label="resources.users.fields.admin" />
<BooleanField source="deactivated" label="resources.users.fields.deactivated" /> <BooleanField source="deactivated" label="resources.users.fields.deactivated" />
<BooleanField source="locked" label="resources.users.fields.locked" /> <BooleanField source="locked" label="resources.users.fields.locked" />
<BooleanField source="suspended" label="resources.users.fields.suspended" />
<BooleanField source="erased" sortable={false} label="resources.users.fields.erased" /> <BooleanField source="erased" sortable={false} label="resources.users.fields.erased" />
<DateField source="creation_ts" label="resources.users.fields.creation_ts_ms" showTime options={DATE_FORMAT} /> <DateField source="creation_ts" label="resources.users.fields.creation_ts_ms" showTime options={DATE_FORMAT} />
</DatagridConfigurable> </DatagridConfigurable>

View File

@ -348,6 +348,10 @@ export interface SynapseDataProvider extends DataProvider {
getAccountData: (id: Identifier) => Promise<AccountDataModel>; getAccountData: (id: Identifier) => Promise<AccountDataModel>;
checkUsernameAvailability: (username: string) => Promise<UsernameAvailabilityResult>; checkUsernameAvailability: (username: string) => Promise<UsernameAvailabilityResult>;
makeRoomAdmin: (room_id: string, user_id: string) => Promise<{ success: boolean; error?: string; errcode?: string }>; makeRoomAdmin: (room_id: string, user_id: string) => Promise<{ success: boolean; error?: string; errcode?: string }>;
suspendUser: (
id: Identifier,
suspendValue: boolean
) => Promise<{ success: boolean; error?: string; errcode?: string }>;
getServerRunningProcess: (etkeAdminUrl: string) => Promise<ServerProcessResponse>; getServerRunningProcess: (etkeAdminUrl: string) => Promise<ServerProcessResponse>;
getServerStatus: (etkeAdminUrl: string) => Promise<ServerStatusResponse>; getServerStatus: (etkeAdminUrl: string) => Promise<ServerStatusResponse>;
getServerNotifications: (etkeAdminUrl: string) => Promise<ServerNotificationsResponse>; getServerNotifications: (etkeAdminUrl: string) => Promise<ServerNotificationsResponse>;
@ -782,6 +786,7 @@ const baseDataProvider: SynapseDataProvider = {
const res = resourceMap[resource]; const res = resourceMap[resource];
const endpoint_url = homeserver + res.path; const endpoint_url = homeserver + res.path;
const { json } = await jsonClient(`${endpoint_url}/${encodeURIComponent(params.id)}`, { const { json } = await jsonClient(`${endpoint_url}/${encodeURIComponent(params.id)}`, {
method: "PUT", method: "PUT",
body: JSON.stringify(params.data, filterNullValues), body: JSON.stringify(params.data, filterNullValues),
@ -1026,6 +1031,22 @@ const baseDataProvider: SynapseDataProvider = {
throw error; throw error;
} }
}, },
suspendUser: async (id: Identifier, suspendValue: boolean) => {
const base_url = localStorage.getItem("base_url");
const endpoint_url = `${base_url}/_synapse/admin/v1/suspend/${encodeURIComponent(returnMXID(id))}`;
try {
const { json } = await jsonClient(endpoint_url, {
method: "PUT",
body: JSON.stringify({ suspend: suspendValue }),
});
return { success: true };
} catch (error) {
if (error instanceof HttpError) {
return { success: false, error: error.body.error, errcode: error.body.errcode };
}
throw error;
}
},
getServerRunningProcess: async (etkeAdminUrl: string, burstCache = false): Promise<ServerProcessResponse> => { getServerRunningProcess: async (etkeAdminUrl: string, burstCache = false): Promise<ServerProcessResponse> => {
const locked_at = ""; const locked_at = "";
const command = ""; const command = "";
@ -1427,12 +1448,18 @@ const dataProvider = withLifecycleCallbacks(baseDataProvider, [
const avatarFile = params.data.avatar_file?.rawFile; const avatarFile = params.data.avatar_file?.rawFile;
const avatarErase = params.data.avatar_erase; const avatarErase = params.data.avatar_erase;
const rates = params.data.rates; const rates = params.data.rates;
const suspended = params.data.suspended;
if (rates) { if (rates) {
await dataProvider.setRateLimits(params.id, rates); await dataProvider.setRateLimits(params.id, rates);
delete params.data.rates; delete params.data.rates;
} }
if (suspended !== undefined) {
await (dataProvider as SynapseDataProvider).suspendUser(params.id, suspended);
delete params.data.suspended;
}
if (avatarErase) { if (avatarErase) {
params.data.avatar_url = ""; params.data.avatar_url = "";
return params; return params;