From 056d9c6b4c56a19c7c6ed1989f80cc9df04ef1b9 Mon Sep 17 00:00:00 2001 From: Borislav Pantaleev Date: Sat, 31 Aug 2024 01:00:29 +0300 Subject: [PATCH] Prevent self user delete --- src/i18n/de.ts | 1 + src/i18n/en.ts | 1 + src/i18n/fr.ts | 1 + src/i18n/index.d.ts | 1 + src/i18n/it.ts | 1 + src/i18n/ru.ts | 1 + src/i18n/zh.ts | 1 + src/resources/users.tsx | 111 ++++++++++++++++++++++++++++++++++------ 8 files changed, 101 insertions(+), 17 deletions(-) diff --git a/src/i18n/de.ts b/src/i18n/de.ts index 9fd96ff..2917b9d 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -142,6 +142,7 @@ const de: SynapseTranslationMessages = { password: "Durch die Änderung des Passworts wird der Benutzer von allen Sitzungen abgemeldet.", deactivate: "Sie müssen ein Passwort angeben, um ein Konto wieder zu aktivieren.", erase: "DSGVO konformes Löschen der Benutzerdaten", + erase_admin_error: "Das Löschen des eigenen Benutzers ist nicht erlaubt", }, action: { erase: "Lösche Benutzerdaten", diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 7577342..c6ef695 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -141,6 +141,7 @@ const en: SynapseTranslationMessages = { password: "Changing password will log user out of all sessions.", deactivate: "You must provide a password to re-activate an account.", erase: "Mark the user as GDPR-erased", + erase_admin_error: "Deleting own user is not allowed.", }, action: { erase: "Erase user data", diff --git a/src/i18n/fr.ts b/src/i18n/fr.ts index af54bd6..b973061 100644 --- a/src/i18n/fr.ts +++ b/src/i18n/fr.ts @@ -139,6 +139,7 @@ const fr: SynapseTranslationMessages = { helper: { deactivate: "Vous devrez fournir un mot de passe pour réactiver le compte.", erase: "Marquer l'utilisateur comme effacé conformément au RGPD", + erase_admin_error: "La suppression de son propre utilisateur n'est pas autorisée.", }, action: { erase: "Effacer les données de l'utilisateur", diff --git a/src/i18n/index.d.ts b/src/i18n/index.d.ts index 38635ad..8a2abb5 100644 --- a/src/i18n/index.d.ts +++ b/src/i18n/index.d.ts @@ -137,6 +137,7 @@ interface SynapseTranslationMessages extends TranslationMessages { password?: string; deactivate: string; erase: string; + erase_admin_error: string; }; action: { erase: string; diff --git a/src/i18n/it.ts b/src/i18n/it.ts index bb813c5..3eedd85 100644 --- a/src/i18n/it.ts +++ b/src/i18n/it.ts @@ -141,6 +141,7 @@ const it: SynapseTranslationMessages = { }, action: { erase: "Cancella i dati dell'utente", + erase_admin_error: "Non è consentito eliminare il proprio utente.", }, }, rooms: { diff --git a/src/i18n/ru.ts b/src/i18n/ru.ts index 5976e11..055479a 100644 --- a/src/i18n/ru.ts +++ b/src/i18n/ru.ts @@ -150,6 +150,7 @@ const ru: SynapseTranslationMessages = { password: "Смена пароля завершит все сессии пользователя.", deactivate: "Вы должны предоставить пароль для реактивации учётной записи.", erase: "Пометить пользователя как удалённого в соответствии с GDPR", + erase_admin_error: "Удаление собственного пользователя запрещено.", }, action: { erase: "Удалить данные пользователя", diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index 86ca9df..eabe806 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -134,6 +134,7 @@ const zh: SynapseTranslationMessages = { helper: { deactivate: "您必须提供一串密码来激活账户。", erase: "将用户标记为根据 GDPR 的要求抹除了", + erase_admin_error: "不允许删除自己的用户", }, action: { erase: "抹除用户信息", diff --git a/src/resources/users.tsx b/src/resources/users.tsx index 2e33df4..eb80dc6 100644 --- a/src/resources/users.tsx +++ b/src/resources/users.tsx @@ -8,6 +8,8 @@ import PermMediaIcon from "@mui/icons-material/PermMedia"; import PersonPinIcon from "@mui/icons-material/PersonPin"; import SettingsInputComponentIcon from "@mui/icons-material/SettingsInputComponent"; import ViewListIcon from "@mui/icons-material/ViewList"; +import { useEffect, useState } from "react"; +import { Alert, ownerDocument } from "@mui/material"; import { ArrayInput, ArrayField, @@ -42,11 +44,15 @@ import { useRecordContext, useTranslate, Pagination, + SaveButton, CreateButton, ExportButton, TopToolbar, + Toolbar, NumberField, useListContext, + useNotify, + ToolbarClasses, } from "react-admin"; import { Link } from "react-router-dom"; @@ -92,16 +98,47 @@ const userFilters = [ , ]; -const UserBulkActionButtons = () => ( - <> +const UserPreventSelfDelete: React.FC<{ children: React.ReactNode, ownUserIsSelected: boolean }> = (props) => { + const ownUserIsSelected = props.ownUserIsSelected; + const notify = useNotify(); + const translate = useTranslate(); + + const handleDeleteClick = (ev: React.MouseEvent) => { + if (ownUserIsSelected) { + notify({translate("resources.users.helper.erase_admin_error")}) + ev.stopPropagation(); + } + }; + + return
+ {props.children} +
+}; + +const UserBulkActionButtons = () => { + const record = useListContext(); + const [ ownUserIsSelected, setOwnUserIsSelected ] = useState(false); + const selectedIds = record.selectedIds; + const ownUserId = localStorage.getItem("user_id"); + const notify = useNotify(); + const translate = useTranslate(); + + useEffect(() => { + setOwnUserIsSelected(selectedIds.includes(ownUserId)); + }, [ selectedIds ]); + + + return <> - + + + -); +}; export const UserList = (props: ListProps) => ( { const record = useRecordContext(); const translate = useTranslate(); + const ownUserId = localStorage.getItem("user_id"); + let ownUserIsSelected = false; + if (record && record.id) { + ownUserIsSelected = record.id === ownUserId; + } return ( {!record?.deactivated && } - + + + ); }; @@ -189,11 +233,44 @@ const UserTitle = () => { ); }; +const UserEditToolbar = () => { + const record = useRecordContext(); + const ownUserId = localStorage.getItem("user_id"); + let ownUserIsSelected = false; + if (record && record.id) { + ownUserIsSelected = record.id === ownUserId; + } + + return <> +
+ + + + + + +
+ +}; + +const UserBooleanInput = (props) => { + const record = useRecordContext(); + const ownUserId = localStorage.getItem("user_id"); + const isOwnUser = false; + let ownUserIsSelected = false; + if (record && (record.id === ownUserId)) { + ownUserIsSelected = true; + } + + return +} + export const UserEdit = (props: EditProps) => { const translate = useTranslate(); + return ( } actions={}> - + }> }> @@ -202,7 +279,7 @@ export const UserEdit = (props: EditProps) => { - +