Compare commits

..

1 Commits

Author SHA1 Message Date
Manuel Stahl b7f009e559 Add buttons to erase users (#32)
Change-Id: I9b5644394d213dc66b30e39f19e9e392b69a0be3
2020-04-09 11:37:02 +02:00
5 changed files with 87 additions and 47 deletions
+1 -2
View File
@@ -25,8 +25,7 @@
"react": "^16.13.1", "react": "^16.13.1",
"react-admin": "^3.4.0", "react-admin": "^3.4.0",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-scripts": "^3.4.1", "react-scripts": "^3.4.1"
"react-admin-import-csv": "^0.2.5"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
+29 -28
View File
@@ -1,4 +1,4 @@
import React from "react"; import React, { Fragment } from "react";
import PersonPinIcon from "@material-ui/icons/PersonPin"; import PersonPinIcon from "@material-ui/icons/PersonPin";
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent"; import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
import { import {
@@ -10,6 +10,7 @@ import {
Edit, Edit,
List, List,
Filter, Filter,
Toolbar,
SimpleForm, SimpleForm,
SimpleFormIterator, SimpleFormIterator,
TabbedForm, TabbedForm,
@@ -21,14 +22,14 @@ import {
TextField, TextField,
TextInput, TextInput,
ReferenceField, ReferenceField,
Toolbar,
TopToolbar,
SelectInput, SelectInput,
BulkDeleteButton,
DeleteButton,
SaveButton,
regex, regex,
useTranslate,
Pagination, Pagination,
} from "react-admin"; } from "react-admin";
import { ImportButton } from "react-admin-import-csv";
import { CreateButton, ExportButton } from "ra-ui-materialui";
const UserPagination = props => ( const UserPagination = props => (
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} /> <Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
@@ -45,28 +46,16 @@ const UserFilter = props => (
</Filter> </Filter>
); );
const ListActions = props => { const UserBulkActionButtons = props => {
const { const translate = useTranslate();
className,
basePath,
total,
resource,
currentSort,
filterValues,
exporter
} = props;
return ( return (
<TopToolbar className={className}> <Fragment>
<CreateButton basePath={basePath} /> <BulkDeleteButton
<ImportButton {...props} /> {...props}
<ExportButton label="resources.users.action.erase"
disabled={total === 0} title={translate("resources.users.helper.erase")}
resource={resource}
sort={currentSort}
filter={filterValues}
exporter={exporter}
/> />
</TopToolbar> </Fragment>
); );
}; };
@@ -75,9 +64,8 @@ export const UserList = props => (
{...props} {...props}
filters={<UserFilter />} filters={<UserFilter />}
filterDefaultValues={{ guests: true, deactivated: false }} filterDefaultValues={{ guests: true, deactivated: false }}
bulkActionButtons={false} bulkActionButtons={<UserBulkActionButtons />}
pagination={<UserPagination />} pagination={<UserPagination />}
actions={<ListActions />}
> >
<Datagrid rowClick="edit"> <Datagrid rowClick="edit">
<ReferenceField <ReferenceField
@@ -111,6 +99,19 @@ const validateUser = regex(
"synapseadmin.users.invalid_user_id" "synapseadmin.users.invalid_user_id"
); );
const UserEditToolbar = props => {
const translate = useTranslate();
return (
<Toolbar {...props}>
<SaveButton submitOnEnter={true} />
<DeleteButton
label="resources.users.action.erase"
title={translate("resources.users.helper.erase")}
/>
</Toolbar>
);
};
export const UserCreate = props => ( export const UserCreate = props => (
<Create {...props}> <Create {...props}>
<SimpleForm> <SimpleForm>
@@ -136,7 +137,7 @@ export const UserCreate = props => (
export const UserEdit = props => ( export const UserEdit = props => (
<Edit {...props}> <Edit {...props}>
<TabbedForm> <TabbedForm toolbar={<UserEditToolbar />}>
<FormTab label="resources.users.name" icon={<PersonPinIcon />}> <FormTab label="resources.users.name" icon={<PersonPinIcon />}>
<TextInput source="id" disabled /> <TextInput source="id" disabled />
<TextInput source="displayname" /> <TextInput source="displayname" />
+4
View File
@@ -37,6 +37,10 @@ export default {
}, },
helper: { helper: {
deactivate: "Deaktivierte Nutzer können nicht wieder aktiviert werden.", deactivate: "Deaktivierte Nutzer können nicht wieder aktiviert werden.",
erase: "DSGVO konformes Löschen der Benutzerdaten",
},
action: {
erase: "Lösche Benutzerdaten",
}, },
}, },
rooms: { rooms: {
+4
View File
@@ -37,6 +37,10 @@ export default {
}, },
helper: { helper: {
deactivate: "Deactivated users cannot be reactivated", deactivate: "Deactivated users cannot be reactivated",
erase: "Mark the user as GDPR-erased",
},
action: {
erase: "Erase user data",
}, },
}, },
rooms: { rooms: {
+49 -17
View File
@@ -30,6 +30,11 @@ const resourceMap = {
? parseInt(json.next_token, 10) + perPage ? parseInt(json.next_token, 10) + perPage
: from + json.users.length; : from + json.users.length;
}, },
delete: id => ({
endpoint: `/_synapse/admin/v1/deactivate/${id}`,
body: { erase: true },
method: "POST",
}),
}, },
rooms: { rooms: {
path: "/_synapse/admin/v1/rooms", path: "/_synapse/admin/v1/rooms",
@@ -202,12 +207,24 @@ const dataProvider = {
const res = resourceMap[resource]; const res = resourceMap[resource];
const homeserver_url = homeserver + res.path; if ("delete" in res) {
return jsonClient(`${homeserver_url}/${params.id}`, { const del = res["delete"](params.id);
method: "DELETE", const homeserver_url = homeserver + del.endpoint;
}).then(({ json }) => ({ return jsonClient(homeserver_url, {
data: json, method: del.method,
})); body: JSON.stringify(del.body),
}).then(({ json }) => ({
data: json,
}));
} else {
const homeserver_url = homeserver + res.path;
return jsonClient(`${homeserver_url}/${params.id}`, {
method: "DELETE",
body: JSON.stringify(params.data, filterNullValues),
}).then(({ json }) => ({
data: json,
}));
}
}, },
deleteMany: (resource, params) => { deleteMany: (resource, params) => {
@@ -217,17 +234,32 @@ const dataProvider = {
const res = resourceMap[resource]; const res = resourceMap[resource];
const homeserver_url = homeserver + res.path; if ("delete" in res) {
return Promise.all( return Promise.all(
params.ids.map(id => params.ids.map(id => {
jsonClient(`${homeserver_url}/${id}`, { const del = res["delete"](id);
method: "DELETE", const homeserver_url = homeserver + del.endpoint;
body: JSON.stringify(params.data, filterNullValues), return jsonClient(homeserver_url, {
}).then(responses => ({ method: del.method,
data: responses.map(({ json }) => json), body: JSON.stringify(del.body),
})) });
) })
); ).then(responses => ({
data: responses.map(({ json }) => json),
}));
} else {
const homeserver_url = homeserver + res.path;
return Promise.all(
params.ids.map(id =>
jsonClient(`${homeserver_url}/${id}`, {
method: "DELETE",
body: JSON.stringify(params.data, filterNullValues),
})
)
).then(responses => ({
data: responses.map(({ json }) => json),
}));
}
}, },
}; };