mirror of
https://github.com/etkecc/synapse-admin.git
synced 2024-11-25 17:15:32 +03:00
Get avatar_url and displayname from v2/users API
API was added by synapse v1.13.0. Change-Id: I927b81882fa20e5b3de3d9fc216e2136f7036bba
This commit is contained in:
parent
8282a3caf8
commit
ab04db5baf
4 changed files with 149 additions and 122 deletions
|
@ -1,4 +1,5 @@
|
||||||
import React, { Fragment } from "react";
|
import React, { Fragment } from "react";
|
||||||
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
import PersonPinIcon from "@material-ui/icons/PersonPin";
|
import PersonPinIcon from "@material-ui/icons/PersonPin";
|
||||||
import ContactMailIcon from "@material-ui/icons/ContactMail";
|
import ContactMailIcon from "@material-ui/icons/ContactMail";
|
||||||
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
|
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
|
||||||
|
@ -18,7 +19,6 @@ import {
|
||||||
FormTab,
|
FormTab,
|
||||||
BooleanField,
|
BooleanField,
|
||||||
BooleanInput,
|
BooleanInput,
|
||||||
ImageField,
|
|
||||||
PasswordInput,
|
PasswordInput,
|
||||||
TextField,
|
TextField,
|
||||||
TextInput,
|
TextInput,
|
||||||
|
@ -32,6 +32,19 @@ import {
|
||||||
Pagination,
|
Pagination,
|
||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices";
|
import { ServerNoticeButton, ServerNoticeBulkButton } from "./ServerNotices";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
|
const useStyles = makeStyles({
|
||||||
|
small: {
|
||||||
|
height: "40px",
|
||||||
|
width: "40px",
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
height: "120px",
|
||||||
|
width: "120px",
|
||||||
|
float: "right",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const UserPagination = props => (
|
const UserPagination = props => (
|
||||||
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||||
|
@ -62,40 +75,36 @@ const UserBulkActionButtons = props => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserList = props => (
|
const AvatarField = ({ source, className, record = {} }) => (
|
||||||
<List
|
<Avatar src={record[source]} className={className} />
|
||||||
{...props}
|
|
||||||
filters={<UserFilter />}
|
|
||||||
filterDefaultValues={{ guests: true, deactivated: false }}
|
|
||||||
bulkActionButtons={<UserBulkActionButtons />}
|
|
||||||
pagination={<UserPagination />}
|
|
||||||
>
|
|
||||||
<Datagrid rowClick="edit">
|
|
||||||
<ReferenceField
|
|
||||||
source="Avatar"
|
|
||||||
reference="users"
|
|
||||||
link={false}
|
|
||||||
sortable={false}
|
|
||||||
>
|
|
||||||
<ImageField source="avatar_url" title="displayname" />
|
|
||||||
</ReferenceField>
|
|
||||||
<TextField source="id" sortable={false} />
|
|
||||||
{/* Hack since the users endpoint does not give displaynames in the list*/}
|
|
||||||
<ReferenceField
|
|
||||||
source="name"
|
|
||||||
reference="users"
|
|
||||||
link={false}
|
|
||||||
sortable={false}
|
|
||||||
>
|
|
||||||
<TextField source="displayname" />
|
|
||||||
</ReferenceField>
|
|
||||||
<BooleanField source="is_guest" sortable={false} />
|
|
||||||
<BooleanField source="admin" sortable={false} />
|
|
||||||
<BooleanField source="deactivated" sortable={false} />
|
|
||||||
</Datagrid>
|
|
||||||
</List>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const UserList = props => {
|
||||||
|
const classes = useStyles();
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
{...props}
|
||||||
|
filters={<UserFilter />}
|
||||||
|
filterDefaultValues={{ guests: true, deactivated: false }}
|
||||||
|
bulkActionButtons={<UserBulkActionButtons />}
|
||||||
|
pagination={<UserPagination />}
|
||||||
|
>
|
||||||
|
<Datagrid rowClick="edit">
|
||||||
|
<AvatarField
|
||||||
|
source="avatar_src"
|
||||||
|
sortable={false}
|
||||||
|
className={classes.small}
|
||||||
|
/>
|
||||||
|
<TextField source="id" sortable={false} />
|
||||||
|
<TextField source="displayname" sortable={false} />
|
||||||
|
<BooleanField source="is_guest" sortable={false} />
|
||||||
|
<BooleanField source="admin" sortable={false} />
|
||||||
|
<BooleanField source="deactivated" sortable={false} />
|
||||||
|
</Datagrid>
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// https://matrix.org/docs/spec/appendices#user-identifiers
|
// https://matrix.org/docs/spec/appendices#user-identifiers
|
||||||
const validateUser = regex(
|
const validateUser = regex(
|
||||||
/^@[a-z0-9._=\-/]+:.*/,
|
/^@[a-z0-9._=\-/]+:.*/,
|
||||||
|
@ -148,89 +157,97 @@ const UserTitle = ({ record }) => {
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export const UserEdit = props => (
|
export const UserEdit = props => {
|
||||||
<Edit {...props} title={<UserTitle />}>
|
const classes = useStyles();
|
||||||
<TabbedForm toolbar={<UserEditToolbar />}>
|
return (
|
||||||
<FormTab label="resources.users.name" icon={<PersonPinIcon />}>
|
<Edit {...props} title={<UserTitle />}>
|
||||||
<TextInput source="id" disabled />
|
<TabbedForm toolbar={<UserEditToolbar />}>
|
||||||
<TextInput source="displayname" />
|
<FormTab label="resources.users.name" icon={<PersonPinIcon />}>
|
||||||
<PasswordInput source="password" autoComplete="new-password" />
|
<AvatarField
|
||||||
<BooleanInput source="admin" />
|
source="avatar_src"
|
||||||
<BooleanInput
|
sortable={false}
|
||||||
source="deactivated"
|
className={classes.large}
|
||||||
helperText="resources.users.helper.deactivate"
|
/>
|
||||||
/>
|
<TextInput source="id" disabled />
|
||||||
<DateField
|
<TextInput source="displayname" />
|
||||||
source="creation_ts_ms"
|
<PasswordInput source="password" autoComplete="new-password" />
|
||||||
showTime
|
<BooleanInput source="admin" />
|
||||||
options={{
|
<BooleanInput
|
||||||
year: "numeric",
|
source="deactivated"
|
||||||
month: "2-digit",
|
helperText="resources.users.helper.deactivate"
|
||||||
day: "2-digit",
|
/>
|
||||||
hour: "2-digit",
|
<DateField
|
||||||
minute: "2-digit",
|
source="creation_ts_ms"
|
||||||
second: "2-digit",
|
showTime
|
||||||
}}
|
options={{
|
||||||
/>
|
year: "numeric",
|
||||||
<TextField source="consent_version" />
|
month: "2-digit",
|
||||||
</FormTab>
|
day: "2-digit",
|
||||||
<FormTab
|
hour: "2-digit",
|
||||||
label="resources.users.threepid"
|
minute: "2-digit",
|
||||||
icon={<ContactMailIcon />}
|
second: "2-digit",
|
||||||
path="threepid"
|
}}
|
||||||
>
|
/>
|
||||||
<ArrayInput source="threepids">
|
<TextField source="consent_version" />
|
||||||
<SimpleFormIterator>
|
</FormTab>
|
||||||
<SelectInput
|
<FormTab
|
||||||
source="medium"
|
label="resources.users.threepid"
|
||||||
choices={[
|
icon={<ContactMailIcon />}
|
||||||
{ id: "email", name: "resources.users.email" },
|
path="threepid"
|
||||||
{ id: "msisdn", name: "resources.users.msisdn" },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<TextInput source="address" />
|
|
||||||
</SimpleFormIterator>
|
|
||||||
</ArrayInput>
|
|
||||||
</FormTab>
|
|
||||||
<FormTab
|
|
||||||
label="resources.connections.name"
|
|
||||||
icon={<SettingsInputComponentIcon />}
|
|
||||||
path="connections"
|
|
||||||
>
|
|
||||||
<ReferenceField
|
|
||||||
reference="connections"
|
|
||||||
source="id"
|
|
||||||
addLabel={false}
|
|
||||||
link={false}
|
|
||||||
>
|
>
|
||||||
<ArrayField
|
<ArrayInput source="threepids">
|
||||||
source="devices[].sessions[0].connections"
|
<SimpleFormIterator>
|
||||||
label="resources.connections.name"
|
<SelectInput
|
||||||
|
source="medium"
|
||||||
|
choices={[
|
||||||
|
{ id: "email", name: "resources.users.email" },
|
||||||
|
{ id: "msisdn", name: "resources.users.msisdn" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<TextInput source="address" />
|
||||||
|
</SimpleFormIterator>
|
||||||
|
</ArrayInput>
|
||||||
|
</FormTab>
|
||||||
|
<FormTab
|
||||||
|
label="resources.connections.name"
|
||||||
|
icon={<SettingsInputComponentIcon />}
|
||||||
|
path="connections"
|
||||||
|
>
|
||||||
|
<ReferenceField
|
||||||
|
reference="connections"
|
||||||
|
source="id"
|
||||||
|
addLabel={false}
|
||||||
|
link={false}
|
||||||
>
|
>
|
||||||
<Datagrid style={{ width: "100%" }}>
|
<ArrayField
|
||||||
<TextField source="ip" sortable={false} />
|
source="devices[].sessions[0].connections"
|
||||||
<DateField
|
label="resources.connections.name"
|
||||||
source="last_seen"
|
>
|
||||||
showTime
|
<Datagrid style={{ width: "100%" }}>
|
||||||
options={{
|
<TextField source="ip" sortable={false} />
|
||||||
year: "numeric",
|
<DateField
|
||||||
month: "2-digit",
|
source="last_seen"
|
||||||
day: "2-digit",
|
showTime
|
||||||
hour: "2-digit",
|
options={{
|
||||||
minute: "2-digit",
|
year: "numeric",
|
||||||
second: "2-digit",
|
month: "2-digit",
|
||||||
}}
|
day: "2-digit",
|
||||||
sortable={false}
|
hour: "2-digit",
|
||||||
/>
|
minute: "2-digit",
|
||||||
<TextField
|
second: "2-digit",
|
||||||
source="user_agent"
|
}}
|
||||||
sortable={false}
|
sortable={false}
|
||||||
style={{ width: "100%" }}
|
/>
|
||||||
/>
|
<TextField
|
||||||
</Datagrid>
|
source="user_agent"
|
||||||
</ArrayField>
|
sortable={false}
|
||||||
</ReferenceField>
|
style={{ width: "100%" }}
|
||||||
</FormTab>
|
/>
|
||||||
</TabbedForm>
|
</Datagrid>
|
||||||
</Edit>
|
</ArrayField>
|
||||||
);
|
</ReferenceField>
|
||||||
|
</FormTab>
|
||||||
|
</TabbedForm>
|
||||||
|
</Edit>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -36,6 +36,7 @@ export default {
|
||||||
displayname: "Anzeigename",
|
displayname: "Anzeigename",
|
||||||
password: "Passwort",
|
password: "Passwort",
|
||||||
avatar_url: "Avatar URL",
|
avatar_url: "Avatar URL",
|
||||||
|
avatar_src: "Avatar",
|
||||||
medium: "Medium",
|
medium: "Medium",
|
||||||
threepids: "3PIDs",
|
threepids: "3PIDs",
|
||||||
address: "Adresse",
|
address: "Adresse",
|
||||||
|
|
|
@ -35,6 +35,7 @@ export default {
|
||||||
displayname: "Displayname",
|
displayname: "Displayname",
|
||||||
password: "Password",
|
password: "Password",
|
||||||
avatar_url: "Avatar URL",
|
avatar_url: "Avatar URL",
|
||||||
|
avatar_src: "Avatar",
|
||||||
medium: "Medium",
|
medium: "Medium",
|
||||||
threepids: "3PIDs",
|
threepids: "3PIDs",
|
||||||
address: "Address",
|
address: "Address",
|
||||||
|
|
|
@ -14,12 +14,24 @@ const jsonClient = (url, options = {}) => {
|
||||||
return fetchUtils.fetchJson(url, options);
|
return fetchUtils.fetchJson(url, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mxcUrlToHttp = mxcUrl => {
|
||||||
|
const homeserver = localStorage.getItem("base_url");
|
||||||
|
const re = /^mxc:\/\/([^/]+)\/(\w+)/;
|
||||||
|
var ret = re.exec(mxcUrl);
|
||||||
|
console.log("mxcClient " + ret);
|
||||||
|
if (ret == null) return null;
|
||||||
|
const serverName = ret[1];
|
||||||
|
const mediaId = ret[2];
|
||||||
|
return `${homeserver}/_matrix/media/r0/thumbnail/${serverName}/${mediaId}?width=24&height=24&method=scale`;
|
||||||
|
};
|
||||||
|
|
||||||
const resourceMap = {
|
const resourceMap = {
|
||||||
users: {
|
users: {
|
||||||
path: "/_synapse/admin/v2/users",
|
path: "/_synapse/admin/v2/users",
|
||||||
map: u => ({
|
map: u => ({
|
||||||
...u,
|
...u,
|
||||||
id: u.name,
|
id: u.name,
|
||||||
|
avatar_src: mxcUrlToHttp(u.avatar_url),
|
||||||
is_guest: !!u.is_guest,
|
is_guest: !!u.is_guest,
|
||||||
admin: !!u.admin,
|
admin: !!u.admin,
|
||||||
deactivated: !!u.deactivated,
|
deactivated: !!u.deactivated,
|
||||||
|
@ -27,11 +39,7 @@ const resourceMap = {
|
||||||
creation_ts_ms: u.creation_ts * 1000,
|
creation_ts_ms: u.creation_ts * 1000,
|
||||||
}),
|
}),
|
||||||
data: "users",
|
data: "users",
|
||||||
total: (json, from, perPage) => {
|
total: json => json.total,
|
||||||
return json.next_token
|
|
||||||
? parseInt(json.next_token, 10) + perPage
|
|
||||||
: from + json.users.length;
|
|
||||||
},
|
|
||||||
create: data => ({
|
create: data => ({
|
||||||
endpoint: `/_synapse/admin/v2/users/${data.id}`,
|
endpoint: `/_synapse/admin/v2/users/${data.id}`,
|
||||||
body: data,
|
body: data,
|
||||||
|
|
Loading…
Reference in a new issue