mirror of
https://github.com/etkecc/synapse-admin.git
synced 2024-11-24 16:45:31 +03:00
Add token based registration creation and management (#200)
* Add token based registration creation and management * yarn fix * Apply suggestions from code review Remove empty line * move date to `const date_format`
This commit is contained in:
parent
c891afa611
commit
efed8b2774
6 changed files with 194 additions and 2 deletions
|
@ -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).
|
||||
|
|
13
src/App.js
13
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}
|
||||
/>
|
||||
<Resource
|
||||
name="registration_tokens"
|
||||
list={RegistrationTokenList}
|
||||
create={RegistrationTokenCreate}
|
||||
edit={RegistrationTokenEdit}
|
||||
icon={ConfirmationNumberIcon}
|
||||
/>
|
||||
<Resource name="connections" />
|
||||
<Resource name="devices" />
|
||||
<Resource name="room_members" />
|
||||
|
|
132
src/components/RegistrationTokens.js
Normal file
132
src/components/RegistrationTokens.js
Normal file
|
@ -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 => (
|
||||
<Filter {...props}>
|
||||
<BooleanInput source="valid" alwaysOn />
|
||||
</Filter>
|
||||
);
|
||||
|
||||
export const RegistrationTokenList = props => {
|
||||
return (
|
||||
<List
|
||||
{...props}
|
||||
filters={<RegistrationTokenFilter />}
|
||||
filterDefaultValues={{ valid: true }}
|
||||
pagination={false}
|
||||
perPage={500}
|
||||
>
|
||||
<Datagrid rowClick="edit">
|
||||
<TextField source="token" sortable={false} />
|
||||
<NumberField source="uses_allowed" sortable={false} />
|
||||
<NumberField source="pending" sortable={false} />
|
||||
<NumberField source="completed" sortable={false} />
|
||||
<DateField
|
||||
source="expiry_time"
|
||||
showTime
|
||||
options={date_format}
|
||||
sortable={false}
|
||||
/>
|
||||
</Datagrid>
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export const RegistrationTokenCreate = props => (
|
||||
<Create {...props}>
|
||||
<SimpleForm redirect="list" toolbar={<Toolbar alwaysEnableSaveButton />}>
|
||||
<TextInput
|
||||
source="token"
|
||||
autoComplete="off"
|
||||
validate={validateToken}
|
||||
resettable
|
||||
/>
|
||||
<NumberInput
|
||||
source="length"
|
||||
validate={validateLength}
|
||||
helperText="resources.registration_tokens.helper.length"
|
||||
step={1}
|
||||
/>
|
||||
<NumberInput
|
||||
source="uses_allowed"
|
||||
validate={validateUsesAllowed}
|
||||
step={1}
|
||||
/>
|
||||
<DateTimeInput source="expiry_time" parse={dateParser} />
|
||||
</SimpleForm>
|
||||
</Create>
|
||||
);
|
||||
|
||||
export const RegistrationTokenEdit = props => {
|
||||
return (
|
||||
<Edit {...props}>
|
||||
<SimpleForm>
|
||||
<TextInput source="token" disabled />
|
||||
<NumberInput source="pending" disabled />
|
||||
<NumberInput source="completed" disabled />
|
||||
<NumberInput
|
||||
source="uses_allowed"
|
||||
validate={validateUsesAllowed}
|
||||
step={1}
|
||||
/>
|
||||
<DateTimeInput
|
||||
source="expiry_time"
|
||||
parse={dateParser}
|
||||
format={dateFormatter}
|
||||
/>
|
||||
</SimpleForm>
|
||||
</Edit>
|
||||
);
|
||||
};
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue