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:
Manuel Stahl 2020-06-10 14:59:55 +02:00
parent 8282a3caf8
commit ab04db5baf
4 changed files with 149 additions and 122 deletions

View file

@ -1,4 +1,5 @@
import React, { Fragment } from "react";
import Avatar from "@material-ui/core/Avatar";
import PersonPinIcon from "@material-ui/icons/PersonPin";
import ContactMailIcon from "@material-ui/icons/ContactMail";
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
@ -18,7 +19,6 @@ import {
FormTab,
BooleanField,
BooleanInput,
ImageField,
PasswordInput,
TextField,
TextInput,
@ -32,6 +32,19 @@ import {
Pagination,
} from "react-admin";
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 => (
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
@ -62,40 +75,36 @@ const UserBulkActionButtons = props => {
);
};
export const UserList = props => (
<List
{...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>
const AvatarField = ({ source, className, record = {} }) => (
<Avatar src={record[source]} className={className} />
);
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
const validateUser = regex(
/^@[a-z0-9._=\-/]+:.*/,
@ -148,89 +157,97 @@ const UserTitle = ({ record }) => {
</span>
);
};
export const UserEdit = props => (
<Edit {...props} title={<UserTitle />}>
<TabbedForm toolbar={<UserEditToolbar />}>
<FormTab label="resources.users.name" icon={<PersonPinIcon />}>
<TextInput source="id" disabled />
<TextInput source="displayname" />
<PasswordInput source="password" autoComplete="new-password" />
<BooleanInput source="admin" />
<BooleanInput
source="deactivated"
helperText="resources.users.helper.deactivate"
/>
<DateField
source="creation_ts_ms"
showTime
options={{
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}}
/>
<TextField source="consent_version" />
</FormTab>
<FormTab
label="resources.users.threepid"
icon={<ContactMailIcon />}
path="threepid"
>
<ArrayInput source="threepids">
<SimpleFormIterator>
<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}
export const UserEdit = props => {
const classes = useStyles();
return (
<Edit {...props} title={<UserTitle />}>
<TabbedForm toolbar={<UserEditToolbar />}>
<FormTab label="resources.users.name" icon={<PersonPinIcon />}>
<AvatarField
source="avatar_src"
sortable={false}
className={classes.large}
/>
<TextInput source="id" disabled />
<TextInput source="displayname" />
<PasswordInput source="password" autoComplete="new-password" />
<BooleanInput source="admin" />
<BooleanInput
source="deactivated"
helperText="resources.users.helper.deactivate"
/>
<DateField
source="creation_ts_ms"
showTime
options={{
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}}
/>
<TextField source="consent_version" />
</FormTab>
<FormTab
label="resources.users.threepid"
icon={<ContactMailIcon />}
path="threepid"
>
<ArrayField
source="devices[].sessions[0].connections"
label="resources.connections.name"
<ArrayInput source="threepids">
<SimpleFormIterator>
<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%" }}>
<TextField source="ip" sortable={false} />
<DateField
source="last_seen"
showTime
options={{
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}}
sortable={false}
/>
<TextField
source="user_agent"
sortable={false}
style={{ width: "100%" }}
/>
</Datagrid>
</ArrayField>
</ReferenceField>
</FormTab>
</TabbedForm>
</Edit>
);
<ArrayField
source="devices[].sessions[0].connections"
label="resources.connections.name"
>
<Datagrid style={{ width: "100%" }}>
<TextField source="ip" sortable={false} />
<DateField
source="last_seen"
showTime
options={{
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
}}
sortable={false}
/>
<TextField
source="user_agent"
sortable={false}
style={{ width: "100%" }}
/>
</Datagrid>
</ArrayField>
</ReferenceField>
</FormTab>
</TabbedForm>
</Edit>
);
};

View file

@ -36,6 +36,7 @@ export default {
displayname: "Anzeigename",
password: "Passwort",
avatar_url: "Avatar URL",
avatar_src: "Avatar",
medium: "Medium",
threepids: "3PIDs",
address: "Adresse",

View file

@ -35,6 +35,7 @@ export default {
displayname: "Displayname",
password: "Password",
avatar_url: "Avatar URL",
avatar_src: "Avatar",
medium: "Medium",
threepids: "3PIDs",
address: "Address",

View file

@ -14,12 +14,24 @@ const jsonClient = (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 = {
users: {
path: "/_synapse/admin/v2/users",
map: u => ({
...u,
id: u.name,
avatar_src: mxcUrlToHttp(u.avatar_url),
is_guest: !!u.is_guest,
admin: !!u.admin,
deactivated: !!u.deactivated,
@ -27,11 +39,7 @@ const resourceMap = {
creation_ts_ms: u.creation_ts * 1000,
}),
data: "users",
total: (json, from, perPage) => {
return json.next_token
? parseInt(json.next_token, 10) + perPage
: from + json.users.length;
},
total: json => json.total,
create: data => ({
endpoint: `/_synapse/admin/v2/users/${data.id}`,
body: data,