From 96942a698b3ea3d974eb64d0ddf4734202736b2b Mon Sep 17 00:00:00 2001
From: dklimpel <5740567+dklimpel@users.noreply.github.com>
Date: Fri, 15 Oct 2021 18:22:21 +0200
Subject: [PATCH] Add token based registration creation and management
---
README.md | 2 +-
src/App.js | 13 +++
src/components/RegistrationTokens.js | 130 +++++++++++++++++++++++++++
src/i18n/de.js | 13 +++
src/i18n/en.js | 13 +++
src/synapse/dataProvider.js | 29 +++++-
6 files changed, 198 insertions(+), 2 deletions(-)
create mode 100644 src/components/RegistrationTokens.js
diff --git a/README.md b/README.md
index 96ab28c..60fc727 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
This project is built using [react-admin](https://marmelab.com/react-admin/).
-It needs at least Synapse v1.38.0 for all functions to work as expected!
+It needs at least Synapse v1.42.0 for all functions to work as expected!
You get your server version with the request `/_synapse/admin/v1/server_version`.
See also [Synapse version API](https://matrix-org.github.io/synapse/develop/admin_api/version_api.html).
diff --git a/src/App.js b/src/App.js
index 018f18c..ee24fac 100644
--- a/src/App.js
+++ b/src/App.js
@@ -8,12 +8,18 @@ import { RoomList, RoomShow } from "./components/rooms";
import { ReportList, ReportShow } from "./components/EventReports";
import LoginPage from "./components/LoginPage";
import UserIcon from "@material-ui/icons/Group";
+import ConfirmationNumberIcon from "@material-ui/icons/ConfirmationNumber";
import EqualizerIcon from "@material-ui/icons/Equalizer";
import { UserMediaStatsList } from "./components/statistics";
import RoomIcon from "@material-ui/icons/ViewList";
import ReportIcon from "@material-ui/icons/Warning";
import FolderSharedIcon from "@material-ui/icons/FolderShared";
import { ImportFeature } from "./components/ImportFeature";
+import {
+ RegistrationTokenCreate,
+ RegistrationTokenEdit,
+ RegistrationTokenList,
+} from "./components/RegistrationTokens";
import { RoomDirectoryList } from "./components/RoomDirectory";
import { Route } from "react-router-dom";
import germanMessages from "./i18n/de";
@@ -66,6 +72,13 @@ const App = () => (
list={RoomDirectoryList}
icon={FolderSharedIcon}
/>
+
diff --git a/src/components/RegistrationTokens.js b/src/components/RegistrationTokens.js
new file mode 100644
index 0000000..beae47b
--- /dev/null
+++ b/src/components/RegistrationTokens.js
@@ -0,0 +1,130 @@
+import React from "react";
+import {
+ BooleanInput,
+ Create,
+ Datagrid,
+ DateField,
+ DateTimeInput,
+ Edit,
+ Filter,
+ List,
+ maxValue,
+ number,
+ NumberField,
+ NumberInput,
+ regex,
+ SimpleForm,
+ TextInput,
+ TextField,
+ Toolbar,
+} from "react-admin";
+
+const validateToken = [regex(/^[A-Za-z0-9._~-]{0,64}$/)];
+const validateUsesAllowed = [number()];
+const validateLength = [number(), maxValue(64)];
+
+const dateParser = v => {
+ const d = new Date(v);
+ if (isNaN(d)) return 0;
+ return d.getTime();
+};
+
+const dateFormatter = v => {
+ if (v === undefined || v === null) return;
+ const d = new Date(v);
+
+ const pad = "00";
+ const year = d.getFullYear().toString();
+ const month = (pad + (d.getMonth() + 1).toString()).slice(-2);
+ const day = (pad + d.getDate().toString()).slice(-2);
+ const hour = (pad + d.getHours().toString()).slice(-2);
+ const minute = (pad + d.getMinutes().toString()).slice(-2);
+
+ // target format yyyy-MM-ddThh:mm
+ return `${year}-${month}-${day}T${hour}:${minute}`;
+};
+
+const RegistrationTokenFilter = props => (
+
+
+
+);
+
+export const RegistrationTokenList = props => {
+ return (
+
}
+ filterDefaultValues={{ valid: true }}
+ pagination={false}
+ perPage={500}
+ >
+
+
+
+
+
+
+
+
+ );
+};
+
+export const RegistrationTokenCreate = props => (
+
+ }>
+
+
+
+
+
+
+);
+
+export const RegistrationTokenEdit = props => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/i18n/de.js b/src/i18n/de.js
index f7b0bb1..b3487a8 100644
--- a/src/i18n/de.js
+++ b/src/i18n/de.js
@@ -353,6 +353,19 @@ const de = {
send_failure: "Beim Entfernen ist ein Fehler aufgetreten.",
},
},
+ registration_tokens: {
+ name: "Registrierungstoken",
+ fields: {
+ token: "Token",
+ valid: "Gültige Token",
+ uses_allowed: "Anzahl",
+ pending: "Ausstehend",
+ completed: "Abgeschlossen",
+ expiry_time: "Ablaufzeit",
+ length: "Länge",
+ },
+ helper: { length: "Länge des Tokens, wenn kein Token vorgegeben wird." },
+ },
},
ra: {
...germanMessages.ra,
diff --git a/src/i18n/en.js b/src/i18n/en.js
index e669a1a..f4a8260 100644
--- a/src/i18n/en.js
+++ b/src/i18n/en.js
@@ -350,5 +350,18 @@ const en = {
},
},
},
+ registration_tokens: {
+ name: "Registration tokens",
+ fields: {
+ token: "Token",
+ valid: "Valid token",
+ uses_allowed: "Uses allowed",
+ pending: "Pending",
+ completed: "Completed",
+ expiry_time: "Expiry time",
+ length: "Length",
+ },
+ helper: { length: "Length of the token if no token is given." },
+ },
};
export default en;
diff --git a/src/synapse/dataProvider.js b/src/synapse/dataProvider.js
index b37af45..d52ce12 100644
--- a/src/synapse/dataProvider.js
+++ b/src/synapse/dataProvider.js
@@ -273,6 +273,25 @@ const resourceMap = {
method: "PUT",
}),
},
+ registration_tokens: {
+ path: "/_synapse/admin/v1/registration_tokens",
+ map: rt => ({
+ ...rt,
+ id: rt.token,
+ }),
+ data: "registration_tokens",
+ total: json => {
+ return json.registration_tokens.length;
+ },
+ create: params => ({
+ endpoint: "/_synapse/admin/v1/registration_tokens/new",
+ body: params,
+ method: "POST",
+ }),
+ delete: params => ({
+ endpoint: `/_synapse/admin/v1/registration_tokens/${params.id}`,
+ }),
+ },
};
function filterNullValues(key, value) {
@@ -294,7 +313,14 @@ function getSearchOrder(order) {
const dataProvider = {
getList: (resource, params) => {
console.log("getList " + resource);
- const { user_id, name, guests, deactivated, search_term } = params.filter;
+ const {
+ user_id,
+ name,
+ guests,
+ deactivated,
+ search_term,
+ valid,
+ } = params.filter;
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const from = (page - 1) * perPage;
@@ -306,6 +332,7 @@ const dataProvider = {
name: name,
guests: guests,
deactivated: deactivated,
+ valid: valid,
order_by: field,
dir: getSearchOrder(order),
};