Improve user account status toggles (#608)
* Enable Erase user if Deactivate is checked * apply lint fixes, update readme
This commit is contained in:
parent
ab247891dc
commit
31356c0bdc
@ -114,6 +114,7 @@ The following changes are already implemented:
|
|||||||
* 🧾 [Make bulk registration CSV import more user-friendly](https://github.com/etkecc/synapse-admin/pull/411)
|
* 🧾 [Make bulk registration CSV import more user-friendly](https://github.com/etkecc/synapse-admin/pull/411)
|
||||||
* 🌐 [Configurable CORS Credentials](https://github.com/etkecc/synapse-admin/pull/456)
|
* 🌐 [Configurable CORS Credentials](https://github.com/etkecc/synapse-admin/pull/456)
|
||||||
* [Do not check homeserver URL during typing in the login form](https://github.com/etkecc/synapse-admin/pull/585)
|
* [Do not check homeserver URL during typing in the login form](https://github.com/etkecc/synapse-admin/pull/585)
|
||||||
|
* [Improve user account status toggles](https://github.com/etkecc/synapse-admin/pull/608)
|
||||||
|
|
||||||
#### exclusive for [etke.cc](https://etke.cc) customers
|
#### exclusive for [etke.cc](https://etke.cc) customers
|
||||||
|
|
||||||
|
@ -209,6 +209,8 @@ const de: SynapseTranslationMessages = {
|
|||||||
suspend:
|
suspend:
|
||||||
"Ein gesperrter Benutzer kann sich nicht mehr anmelden und wird in den schreibgeschützten Modus versetzt.",
|
"Ein gesperrter Benutzer kann sich nicht mehr anmelden und wird in den schreibgeschützten Modus versetzt.",
|
||||||
erase: "DSGVO konformes Löschen der Benutzerdaten.",
|
erase: "DSGVO konformes Löschen der Benutzerdaten.",
|
||||||
|
admin: "Ein Serveradministrator hat volle Kontrolle über den Server und seine Benutzer.",
|
||||||
|
lock: "Verhindert, dass der Benutzer den Server nutzen kann. Dies ist eine nicht-destruktive Aktion, die rückgängig gemacht werden kann.",
|
||||||
erase_text:
|
erase_text:
|
||||||
"Das bedeutet, dass die von dem/den Benutzer(n) gesendeten Nachrichten für alle, die zum Zeitpunkt des Sendens im Raum waren, sichtbar bleiben, aber für Benutzer, die dem Raum später beitreten, nicht sichtbar sind.",
|
"Das bedeutet, dass die von dem/den Benutzer(n) gesendeten Nachrichten für alle, die zum Zeitpunkt des Sendens im Raum waren, sichtbar bleiben, aber für Benutzer, die dem Raum später beitreten, nicht sichtbar sind.",
|
||||||
erase_admin_error: "Das Löschen des eigenen Benutzers ist nicht erlaubt.",
|
erase_admin_error: "Das Löschen des eigenen Benutzers ist nicht erlaubt.",
|
||||||
|
@ -172,9 +172,11 @@ const en: SynapseTranslationMessages = {
|
|||||||
helper: {
|
helper: {
|
||||||
password: "Changing password will log user out of all sessions.",
|
password: "Changing password will log user out of all sessions.",
|
||||||
create_password: "Generate a strong and secure password using the button below.",
|
create_password: "Generate a strong and secure password using the button below.",
|
||||||
|
lock: "Prevent the user from usefully using their account. This is a non-destructive action that can be reversed.",
|
||||||
deactivate: "You must provide a password to re-activate an account.",
|
deactivate: "You must provide a password to re-activate an account.",
|
||||||
suspend: "Suspending user means they are put into a read-only mode.",
|
suspend: "Suspending user means they are put into a read-only mode.",
|
||||||
erase: "Mark the user as GDPR-erased",
|
erase: "In addition to deactivating the user, mark the user as GDPR-erased.",
|
||||||
|
admin: "A server administrator has full control over the server and its users.",
|
||||||
erase_text:
|
erase_text:
|
||||||
"This means messages sent by the user(-s) will still be visible by anyone who was in the room when these messages were sent, but hidden from users joining the room afterward.",
|
"This means messages sent by the user(-s) will still be visible by anyone who was in the room when these messages were sent, but hidden from users joining the room afterward.",
|
||||||
erase_admin_error: "Deleting own user is not allowed.",
|
erase_admin_error: "Deleting own user is not allowed.",
|
||||||
|
@ -162,6 +162,8 @@ const fa: SynapseTranslationMessages = {
|
|||||||
user_type: "نوع کاربر",
|
user_type: "نوع کاربر",
|
||||||
},
|
},
|
||||||
helper: {
|
helper: {
|
||||||
|
admin: "مدیر سرور دارای کنترل کامل بر روی سرور و کاربران آن است.",
|
||||||
|
lock: "ممنوعیت استفاده از سرور توسط کاربر. این یک عملیات غیر مخرب است که می تواند برگردانده شود.",
|
||||||
password: "با تغییر رمز عبور کاربر از تمام دستگاه ها خارج می شود.",
|
password: "با تغییر رمز عبور کاربر از تمام دستگاه ها خارج می شود.",
|
||||||
create_password: "رمز عبور قوی و امنی را با استفاده از دکمه زیر ایجاد کنید.",
|
create_password: "رمز عبور قوی و امنی را با استفاده از دکمه زیر ایجاد کنید.",
|
||||||
deactivate: "برای فعالسازی مجدد حساب باید رمز عبور وارد کنید.",
|
deactivate: "برای فعالسازی مجدد حساب باید رمز عبور وارد کنید.",
|
||||||
|
@ -174,6 +174,8 @@ const fr: SynapseTranslationMessages = {
|
|||||||
deactivate: "Vous devrez fournir un mot de passe pour réactiver le compte.",
|
deactivate: "Vous devrez fournir un mot de passe pour réactiver le compte.",
|
||||||
suspend: "L'utilisateur sera suspendu jusqu'à ce que vous le réactiviez.",
|
suspend: "L'utilisateur sera suspendu jusqu'à ce que vous le réactiviez.",
|
||||||
erase: "Marquer l'utilisateur comme effacé conformément au RGPD",
|
erase: "Marquer l'utilisateur comme effacé conformément au RGPD",
|
||||||
|
admin: "Un administrateur de serveur a un contrôle total sur le serveur et ses utilisateurs.",
|
||||||
|
lock: "Empêche l'utilisateur d'utiliser le serveur. C'est une action non destructive qui peut être annulée.",
|
||||||
erase_text:
|
erase_text:
|
||||||
"Cela signifie que les messages envoyés par le(s) utilisateur(s) seront toujours visibles par toute personne qui se trouvait dans la salle au moment où ces messages ont été envoyés, mais qu'ils seront cachés aux utilisateurs qui rejoindront la salle par la suite.",
|
"Cela signifie que les messages envoyés par le(s) utilisateur(s) seront toujours visibles par toute personne qui se trouvait dans la salle au moment où ces messages ont été envoyés, mais qu'ils seront cachés aux utilisateurs qui rejoindront la salle par la suite.",
|
||||||
erase_admin_error: "La suppression de son propre utilisateur n'est pas autorisée.",
|
erase_admin_error: "La suppression de son propre utilisateur n'est pas autorisée.",
|
||||||
|
2
src/i18n/index.d.ts
vendored
2
src/i18n/index.d.ts
vendored
@ -162,8 +162,10 @@ interface SynapseTranslationMessages extends TranslationMessages {
|
|||||||
helper: {
|
helper: {
|
||||||
password: string;
|
password: string;
|
||||||
create_password: string;
|
create_password: string;
|
||||||
|
lock: string;
|
||||||
deactivate: string;
|
deactivate: string;
|
||||||
suspend: string;
|
suspend: string;
|
||||||
|
admin: string;
|
||||||
erase: string;
|
erase: string;
|
||||||
erase_text: string;
|
erase_text: string;
|
||||||
erase_admin_error: string;
|
erase_admin_error: string;
|
||||||
|
@ -167,6 +167,8 @@ const it: SynapseTranslationMessages = {
|
|||||||
deactivate: "Devi fornire una password per riattivare l'account.",
|
deactivate: "Devi fornire una password per riattivare l'account.",
|
||||||
suspend: "Sospendi l'utente",
|
suspend: "Sospendi l'utente",
|
||||||
erase: "Constrassegna l'utente come cancellato dal GDPR",
|
erase: "Constrassegna l'utente come cancellato dal GDPR",
|
||||||
|
admin: "Un amministratore del server ha controllo totale sul server e sui suoi utenti.",
|
||||||
|
lock: "Impedisce all'utente di utilizzare il server. Questa è un'azione non distruttiva che può essere annullata.",
|
||||||
erase_text:
|
erase_text:
|
||||||
"Ciò significa che i messaggi inviati dall'utente (o dagli utenti) saranno ancora visibili da chiunque si trovasse nella stanza al momento dell'invio, ma saranno nascosti agli utenti che si uniranno alla stanza in seguito.",
|
"Ciò significa che i messaggi inviati dall'utente (o dagli utenti) saranno ancora visibili da chiunque si trovasse nella stanza al momento dell'invio, ma saranno nascosti agli utenti che si uniranno alla stanza in seguito.",
|
||||||
erase_admin_error: "Non è consentito eliminare il proprio utente.",
|
erase_admin_error: "Non è consentito eliminare il proprio utente.",
|
||||||
|
@ -213,6 +213,8 @@ const ru: SynapseTranslationMessages = {
|
|||||||
suspend:
|
suspend:
|
||||||
"Приостановка учётной записи означает, что пользователь не сможет войти в свою учётную запись, пока она не будет снова активирована.",
|
"Приостановка учётной записи означает, что пользователь не сможет войти в свою учётную запись, пока она не будет снова активирована.",
|
||||||
erase: "Пометить пользователя как удалённого в соответствии с GDPR",
|
erase: "Пометить пользователя как удалённого в соответствии с GDPR",
|
||||||
|
admin: "Администратор сервера имеет полный контроль над сервером и его пользователями.",
|
||||||
|
lock: "Предотвращает использование пользователем сервера. Это неразрушающее действие, которое может быть отменено.",
|
||||||
erase_text:
|
erase_text:
|
||||||
"Это означает, что сообщения, отправленные пользователем (-ами), будут по-прежнему видны всем, кто находился в комнате в момент их отправки, но будут скрыты от пользователей, присоединившихся к комнате после этого.",
|
"Это означает, что сообщения, отправленные пользователем (-ами), будут по-прежнему видны всем, кто находился в комнате в момент их отправки, но будут скрыты от пользователей, присоединившихся к комнате после этого.",
|
||||||
erase_admin_error: "Удаление собственного пользователя запрещено.",
|
erase_admin_error: "Удаление собственного пользователя запрещено.",
|
||||||
|
@ -197,6 +197,8 @@ const zh: SynapseTranslationMessages = {
|
|||||||
deactivate: "您必须提供一串密码来激活账户。",
|
deactivate: "您必须提供一串密码来激活账户。",
|
||||||
suspend: "您必须提供一串密码来暂停账户。",
|
suspend: "您必须提供一串密码来暂停账户。",
|
||||||
erase: "将用户标记为根据 GDPR 的要求抹除了",
|
erase: "将用户标记为根据 GDPR 的要求抹除了",
|
||||||
|
admin: "服务器管理员对服务器和其用户有完全的控制权。",
|
||||||
|
lock: "阻止用户使用服务器。这是一个非破坏性的操作,可以被撤销。",
|
||||||
erase_text:
|
erase_text:
|
||||||
"这意味着用户发送的信息对于发送信息时在房间内的任何人来说都是可见的,但对于之后加入房间的用户来说则是隐藏的。",
|
"这意味着用户发送的信息对于发送信息时在房间内的任何人来说都是可见的,但对于之后加入房间的用户来说则是隐藏的。",
|
||||||
erase_admin_error: "不允许删除自己的用户",
|
erase_admin_error: "不允许删除自己的用户",
|
||||||
|
@ -426,7 +426,7 @@ const UserBooleanInput = props => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<UserPreventSelfDelete ownUserIsSelected={ownUserIsSelected} asManagedUserIsSelected={asManagedUserIsSelected}>
|
<UserPreventSelfDelete ownUserIsSelected={ownUserIsSelected} asManagedUserIsSelected={asManagedUserIsSelected}>
|
||||||
<BooleanInput {...props} disabled={ownUserIsSelected || asManagedUserIsSelected} />
|
<BooleanInput disabled={ownUserIsSelected || asManagedUserIsSelected} {...props} />
|
||||||
</UserPreventSelfDelete>
|
</UserPreventSelfDelete>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -470,8 +470,28 @@ const UserPasswordInput = props => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ErasedBooleanInput = props => {
|
||||||
|
const record = useRecordContext();
|
||||||
|
const form = useFormContext();
|
||||||
|
const deactivated = form.watch("deactivated");
|
||||||
|
const erased = form.watch("erased");
|
||||||
|
|
||||||
|
const erasedFromRecord = record?.erased;
|
||||||
|
const deactivatedFromRecord = record?.deactivated;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// If the user was erased and deactivated, by unchecking Erased, we want to also uncheck Deactivated
|
||||||
|
if (erasedFromRecord === true && erased === false) {
|
||||||
|
form.setValue("deactivated", false);
|
||||||
|
}
|
||||||
|
}, [deactivatedFromRecord, erased, erasedFromRecord]);
|
||||||
|
|
||||||
|
return <UserBooleanInput disabled={!deactivated} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
export const UserEdit = (props: EditProps) => {
|
export const UserEdit = (props: EditProps) => {
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit
|
<Edit
|
||||||
@ -515,12 +535,24 @@ export const UserEdit = (props: EditProps) => {
|
|||||||
helperText="resources.users.helper.password"
|
helperText="resources.users.helper.password"
|
||||||
/>
|
/>
|
||||||
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
<SelectInput source="user_type" choices={choices_type} translateChoice={false} resettable />
|
||||||
<BooleanInput source="admin" />
|
<BooleanInput source="admin" helperText="resources.users.helper.admin" />
|
||||||
<UserBooleanInput source="locked" />
|
|
||||||
<UserBooleanInput source="deactivated" helperText="resources.users.helper.deactivate" />
|
|
||||||
<UserBooleanInput source="suspended" helperText="resources.users.helper.suspend" />
|
<UserBooleanInput source="suspended" helperText="resources.users.helper.suspend" />
|
||||||
<BooleanInput source="erased" disabled />
|
<UserBooleanInput
|
||||||
<DateField source="creation_ts_ms" showTime options={DATE_FORMAT} />
|
sx={{ color: theme.palette.warning.main }}
|
||||||
|
source="locked"
|
||||||
|
helperText="resources.users.helper.lock"
|
||||||
|
/>
|
||||||
|
<UserBooleanInput
|
||||||
|
sx={{ color: theme.palette.error.main }}
|
||||||
|
source="deactivated"
|
||||||
|
helperText="resources.users.helper.deactivate"
|
||||||
|
/>
|
||||||
|
<ErasedBooleanInput
|
||||||
|
sx={{ color: theme.palette.error.main, marginLeft: "25px" }}
|
||||||
|
source="erased"
|
||||||
|
helperText="resources.users.helper.erase"
|
||||||
|
/>
|
||||||
|
<DateField sx={{ marginTop: "20px" }} source="creation_ts_ms" showTime options={DATE_FORMAT} />
|
||||||
<TextField source="consent_version" />
|
<TextField source="consent_version" />
|
||||||
</FormTab>
|
</FormTab>
|
||||||
|
|
||||||
|
@ -352,6 +352,7 @@ export interface SynapseDataProvider extends DataProvider {
|
|||||||
id: Identifier,
|
id: Identifier,
|
||||||
suspendValue: boolean
|
suspendValue: boolean
|
||||||
) => Promise<{ success: boolean; error?: string; errcode?: string }>;
|
) => Promise<{ success: boolean; error?: string; errcode?: string }>;
|
||||||
|
eraseUser: (id: Identifier) => 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>;
|
||||||
@ -1047,6 +1048,22 @@ const baseDataProvider: SynapseDataProvider = {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
eraseUser: async (id: Identifier) => {
|
||||||
|
const base_url = localStorage.getItem("base_url");
|
||||||
|
const endpoint_url = `${base_url}/_synapse/admin/v1/deactivate/${encodeURIComponent(returnMXID(id))}`;
|
||||||
|
try {
|
||||||
|
await jsonClient(endpoint_url, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ erase: true }),
|
||||||
|
});
|
||||||
|
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 = "";
|
||||||
@ -1449,17 +1466,26 @@ const dataProvider = withLifecycleCallbacks(baseDataProvider, [
|
|||||||
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;
|
const suspended = params.data.suspended;
|
||||||
|
const previousSuspended = params.previousData?.suspended;
|
||||||
|
const deactivated = params.data.deactivated;
|
||||||
|
const erased = params.data.erased;
|
||||||
|
|
||||||
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) {
|
if (suspended !== undefined && suspended !== previousSuspended) {
|
||||||
await (dataProvider as SynapseDataProvider).suspendUser(params.id, suspended);
|
await (dataProvider as SynapseDataProvider).suspendUser(params.id, suspended);
|
||||||
delete params.data.suspended;
|
delete params.data.suspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deactivated !== undefined && erased !== undefined) {
|
||||||
|
await (dataProvider as SynapseDataProvider).eraseUser(params.id);
|
||||||
|
delete params.data.deactivated;
|
||||||
|
delete params.data.erased;
|
||||||
|
}
|
||||||
|
|
||||||
if (avatarErase) {
|
if (avatarErase) {
|
||||||
params.data.avatar_url = "";
|
params.data.avatar_url = "";
|
||||||
return params;
|
return params;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user