diff --git a/README.md b/README.md
index 1ab9552..85ee974 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.41.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..28213e5
--- /dev/null
+++ b/src/components/RegistrationTokens.js
@@ -0,0 +1,132 @@
+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 date_format = {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
+ second: "2-digit",
+};
+
+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 9688468..81889ed 100644
--- a/src/i18n/de.js
+++ b/src/i18n/de.js
@@ -352,6 +352,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 b1e379a..fb63005 100644
--- a/src/i18n/en.js
+++ b/src/i18n/en.js
@@ -351,5 +351,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 5b11139..b80b075 100644
--- a/src/synapse/dataProvider.js
+++ b/src/synapse/dataProvider.js
@@ -275,6 +275,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) {
@@ -296,7 +315,8 @@ 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;
@@ -308,6 +328,7 @@ const dataProvider = {
name: name,
guests: guests,
deactivated: deactivated,
+ valid: valid,
order_by: field,
dir: getSearchOrder(order),
};