From 314906657f4e69f0d5e2d776cb65912208e74af2 Mon Sep 17 00:00:00 2001 From: Manuel Stahl Date: Wed, 8 Jul 2020 11:11:24 +0200 Subject: [PATCH] Add support to remove user devices (#57) Change-Id: I19176daa656b9280ccd00f1ca0095e72870ca21e --- src/components/devices.js | 89 +++++++++++++++++++++++++++++++++++++ src/components/users.js | 2 + src/i18n/de.js | 8 ++++ src/i18n/en.js | 8 ++++ src/synapse/dataProvider.js | 19 ++++---- 5 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 src/components/devices.js diff --git a/src/components/devices.js b/src/components/devices.js new file mode 100644 index 0000000..ee9292c --- /dev/null +++ b/src/components/devices.js @@ -0,0 +1,89 @@ +import React, { Fragment, useState } from "react"; +import { + Button, + useMutation, + useNotify, + Confirm, + useRefresh, +} from "react-admin"; +import ActionDelete from "@material-ui/icons/Delete"; +import { makeStyles } from "@material-ui/core/styles"; +import { fade } from "@material-ui/core/styles/colorManipulator"; +import classnames from "classnames"; + +const useStyles = makeStyles( + theme => ({ + deleteButton: { + color: theme.palette.error.main, + "&:hover": { + backgroundColor: fade(theme.palette.error.main, 0.12), + // Reset on mouse devices + "@media (hover: none)": { + backgroundColor: "transparent", + }, + }, + }, + }), + { name: "RaDeleteDeviceButton" } +); + +export const DeviceRemoveButton = props => { + const { record } = props; + const classes = useStyles(props); + const [open, setOpen] = useState(false); + const refresh = useRefresh(); + const notify = useNotify(); + + const [removeDevice, { loading }] = useMutation(); + + if (!record) return null; + + const handleClick = () => setOpen(true); + const handleDialogClose = () => setOpen(false); + + const handleConfirm = () => { + removeDevice( + { + type: "delete", + resource: "devices", + payload: { + id: record.id, + user_id: record.user_id, + }, + }, + { + onSuccess: () => { + notify("resources.devices.action.erase.success"); + refresh(); + }, + onFailure: () => + notify("resources.devices.action.erase.failure", "error"), + } + ); + setOpen(false); + }; + + return ( + + + + + ); +}; diff --git a/src/components/users.js b/src/components/users.js index cb98cd9..a6889b2 100644 --- a/src/components/users.js +++ b/src/components/users.js @@ -38,6 +38,7 @@ import { sanitizeListRestProps, } from "react-admin"; import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices"; +import { DeviceRemoveButton } from "./devices"; import { makeStyles } from "@material-ui/core/styles"; const useStyles = makeStyles({ @@ -284,6 +285,7 @@ export const UserEdit = props => { }} sortable={false} /> + diff --git a/src/i18n/de.js b/src/i18n/de.js index 3f95a1d..0243041 100644 --- a/src/i18n/de.js +++ b/src/i18n/de.js @@ -114,6 +114,14 @@ export default { }, devices: { name: "Gerät |||| Geräte", + action: { + erase: { + title: "Entferne %{id}", + content: 'Möchten Sie das Gerät "%{name}" wirklich entfernen?', + success: "Gerät erfolgreich entfernt.", + failure: "Beim Entfernen ist ein Fehler aufgetreten.", + }, + }, }, servernotices: { name: "Serverbenachrichtigungen", diff --git a/src/i18n/en.js b/src/i18n/en.js index cc98c6b..f6501c9 100644 --- a/src/i18n/en.js +++ b/src/i18n/en.js @@ -112,6 +112,14 @@ export default { }, devices: { name: "Device |||| Devices", + action: { + erase: { + title: "Removing %{id}", + content: 'Are you sure you want to remove the device "%{name}"?', + success: "Device successfully removed.", + failure: "An error has occurred.", + }, + }, }, servernotices: { name: "Server Notices", diff --git a/src/synapse/dataProvider.js b/src/synapse/dataProvider.js index 674d935..d4c8bcd 100644 --- a/src/synapse/dataProvider.js +++ b/src/synapse/dataProvider.js @@ -45,8 +45,8 @@ const resourceMap = { body: data, method: "PUT", }), - delete: id => ({ - endpoint: `/_synapse/admin/v1/deactivate/${id}`, + delete: params => ({ + endpoint: `/_synapse/admin/v1/deactivate/${params.id}`, body: { erase: true }, method: "POST", }), @@ -76,6 +76,9 @@ const resourceMap = { reference: id => ({ endpoint: `/_synapse/admin/v2/users/${id}/devices`, }), + delete: params => ({ + endpoint: `/_synapse/admin/v2/users/${params.user_id}/devices/${params.id}`, + }), }, connections: { path: "/_synapse/admin/v1/whois", @@ -274,11 +277,11 @@ const dataProvider = { const res = resourceMap[resource]; if ("delete" in res) { - const del = res["delete"](params.id); + const del = res["delete"](params); const endpoint_url = homeserver + del.endpoint; return jsonClient(endpoint_url, { - method: del.method, - body: JSON.stringify(del.body), + method: "method" in del ? del.method : "DELETE", + body: "body" in del ? JSON.stringify(del.body) : null, }).then(({ json }) => ({ data: json, })); @@ -303,11 +306,11 @@ const dataProvider = { if ("delete" in res) { return Promise.all( params.ids.map(id => { - const del = res["delete"](id); + const del = res["delete"]({ ...params, id: id }); const endpoint_url = homeserver + del.endpoint; return jsonClient(endpoint_url, { - method: del.method, - body: JSON.stringify(del.body), + method: "method" in del ? del.method : "DELETE", + body: "body" in del ? JSON.stringify(del.body) : null, }); }) ).then(responses => ({