Merge branch 'master' into password-change-warning
This commit is contained in:
commit
d4291e49dd
2
.github/workflows/build-test.yml
vendored
2
.github/workflows/build-test.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version: 16
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn --frozen-lockfile
|
run: yarn --frozen-lockfile
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
31
.github/workflows/docker-release.yml
vendored
31
.github/workflows/docker-release.yml
vendored
@ -2,8 +2,14 @@ name: Create docker image(s) and push to docker hub
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
# Sequence of patterns matched against refs/heads
|
||||||
- '[0-9]+\.[0-9]+\.[0-9]+'
|
# prettier-ignore
|
||||||
|
branches:
|
||||||
|
# Push events on master branch
|
||||||
|
- master
|
||||||
|
# Sequence of patterns matched against refs/tags
|
||||||
|
tags:
|
||||||
|
- '[0-9]+\.[0-9]+\.[0-9]+' # Push events to 0.X.X tag
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
docker:
|
docker:
|
||||||
@ -21,10 +27,25 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Calculate docker image tag
|
||||||
|
id: set-tag
|
||||||
|
run: |
|
||||||
|
case "${GITHUB_REF}" in
|
||||||
|
refs/heads/master|refs/heads/main)
|
||||||
|
tag=latest
|
||||||
|
;;
|
||||||
|
refs/tags/*)
|
||||||
|
tag=${GITHUB_REF#refs/tags/}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
tag=${GITHUB_SHA}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "::set-output name=tag::$tag"
|
||||||
|
- name: Build and Push Tag
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
push: true
|
||||||
tags: awesometechnologies/synapse-admin:latest
|
tags: "awesometechnologies/synapse-admin:${{ steps.set-tag.outputs.tag }}"
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
26
.github/workflows/edge_ghpage.yml
vendored
Normal file
26
.github/workflows/edge_ghpage.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Build and Deploy Edge version to GH Pages
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout 🛎️
|
||||||
|
uses: actions/checkout@v2.3.1
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: "16"
|
||||||
|
- name: Install and Build 🔧
|
||||||
|
run: |
|
||||||
|
yarn install
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
- name: Deploy 🚀
|
||||||
|
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||||
|
with:
|
||||||
|
branch: gh-pages
|
||||||
|
folder: build
|
2
.github/workflows/github-release.yml
vendored
2
.github/workflows/github-release.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: "14"
|
node-version: "16"
|
||||||
- run: yarn install
|
- run: yarn install
|
||||||
- run: yarn build
|
- run: yarn build
|
||||||
- run: |
|
- run: |
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"jsxBracketSameLine": false,
|
"jsxBracketSameLine": false,
|
||||||
"arrowParens": "avoid",
|
"arrowParens": "avoid"
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
# Builder
|
# Builder
|
||||||
FROM node:lts as builder
|
FROM node:lts as builder
|
||||||
|
|
||||||
|
ARG PUBLIC_URL=/
|
||||||
|
ARG REACT_APP_SERVER
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
COPY . /src
|
COPY . /src
|
||||||
RUN yarn --network-timeout=100000 install
|
RUN yarn --network-timeout=100000 install
|
||||||
RUN yarn build
|
RUN PUBLIC_URL=$PUBLIC_URL REACT_APP_SERVER=$REACT_APP_SERVER yarn build
|
||||||
|
|
||||||
|
|
||||||
# App
|
# App
|
||||||
|
35
README.md
35
README.md
@ -5,13 +5,19 @@
|
|||||||
|
|
||||||
This project is built using [react-admin](https://marmelab.com/react-admin/).
|
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!
|
## Usage
|
||||||
|
|
||||||
|
### Supported Synapse
|
||||||
|
|
||||||
|
It needs at least [Synapse](https://github.com/matrix-org/synapse) v1.46.0 for all functions to work as expected!
|
||||||
|
|
||||||
You get your server version with the request `/_synapse/admin/v1/server_version`.
|
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).
|
See also [Synapse version API](https://matrix-org.github.io/synapse/develop/admin_api/version_api.html).
|
||||||
|
|
||||||
After entering the URL on the login page of synapse-admin the server version appears below the input field.
|
After entering the URL on the login page of synapse-admin the server version appears below the input field.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
You need access to the following endpoints:
|
You need access to the following endpoints:
|
||||||
|
|
||||||
- `/_matrix`
|
- `/_matrix`
|
||||||
@ -19,15 +25,25 @@ You need access to the following endpoints:
|
|||||||
|
|
||||||
See also [Synapse administration endpoints](https://matrix-org.github.io/synapse/develop/reverse_proxy.html#synapse-administration-endpoints)
|
See also [Synapse administration endpoints](https://matrix-org.github.io/synapse/develop/reverse_proxy.html#synapse-administration-endpoints)
|
||||||
|
|
||||||
## Step-By-Step install:
|
### Use without install
|
||||||
|
|
||||||
|
You can use the current version of Synapse Admin without own installation direct
|
||||||
|
via [GitHub Pages](https://awesome-technologies.github.io/synapse-admin/).
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
If you want to use the deployment, you have to make sure that the admin endpoints (`/_synapse/admin`) are accessible for your browser.
|
||||||
|
**Remember: You have no need to expose these endpoints to the internet but to your network.**
|
||||||
|
If you want your own deployment, follow the [Step-By-Step Install Guide](#step-by-step-install) below.
|
||||||
|
|
||||||
|
### Step-By-Step install
|
||||||
|
|
||||||
You have three options:
|
You have three options:
|
||||||
|
|
||||||
1. Download the tarball and serve with any webserver
|
1. [Download the tarball and serve with any webserver](#steps-for-1)
|
||||||
2. Download the source code from github and run using nodejs
|
2. [Download the source code from github and run using nodejs](#steps-for-2)
|
||||||
3. Run the Docker container
|
3. [Run the Docker container](#steps-for-3)
|
||||||
|
|
||||||
Steps for 1):
|
#### Steps for 1)
|
||||||
|
|
||||||
- make sure you have a webserver installed that can serve static files (any webserver like nginx or apache will do)
|
- make sure you have a webserver installed that can serve static files (any webserver like nginx or apache will do)
|
||||||
- configure a vhost for synapse admin on your webserver
|
- configure a vhost for synapse admin on your webserver
|
||||||
@ -36,7 +52,7 @@ Steps for 1):
|
|||||||
- move or symlink the `synapse-admin-x.x.x` into your vhosts root dir
|
- move or symlink the `synapse-admin-x.x.x` into your vhosts root dir
|
||||||
- open the url of the vhost in your browser
|
- open the url of the vhost in your browser
|
||||||
|
|
||||||
Steps for 2):
|
#### Steps for 2)
|
||||||
|
|
||||||
- make sure you have installed the following: git, yarn, nodejs
|
- make sure you have installed the following: git, yarn, nodejs
|
||||||
- download the source code: `git clone https://github.com/Awesome-Technologies/synapse-admin.git`
|
- download the source code: `git clone https://github.com/Awesome-Technologies/synapse-admin.git`
|
||||||
@ -49,7 +65,7 @@ Either you define it at startup (e.g. `REACT_APP_SERVER=https://yourmatrixserver
|
|||||||
or by editing it in the [.env](.env) file. See also the
|
or by editing it in the [.env](.env) file. See also the
|
||||||
[documentation](https://create-react-app.dev/docs/adding-custom-environment-variables/).
|
[documentation](https://create-react-app.dev/docs/adding-custom-environment-variables/).
|
||||||
|
|
||||||
Steps for 3):
|
#### Steps for 3)
|
||||||
|
|
||||||
- run the Docker container from the public docker registry: `docker run -p 8080:80 awesometechnologies/synapse-admin` or use the [docker-compose.yml](docker-compose.yml): `docker-compose up -d`
|
- run the Docker container from the public docker registry: `docker run -p 8080:80 awesometechnologies/synapse-admin` or use the [docker-compose.yml](docker-compose.yml): `docker-compose up -d`
|
||||||
|
|
||||||
@ -66,6 +82,9 @@ Steps for 3):
|
|||||||
context: https://github.com/Awesome-Technologies/synapse-admin.git
|
context: https://github.com/Awesome-Technologies/synapse-admin.git
|
||||||
# args:
|
# args:
|
||||||
# - NODE_OPTIONS="--max_old_space_size=1024"
|
# - NODE_OPTIONS="--max_old_space_size=1024"
|
||||||
|
# # see #266
|
||||||
|
# - PUBLIC_URL="/synapse-admin"
|
||||||
|
# - REACT_APP_SERVER="https://matrix.example.com"
|
||||||
ports:
|
ports:
|
||||||
- "8080:80"
|
- "8080:80"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "synapse-admin",
|
"name": "synapse-admin",
|
||||||
"version": "0.8.3",
|
"version": "0.8.5",
|
||||||
"description": "Admin GUI for the Matrix.org server Synapse",
|
"description": "Admin GUI for the Matrix.org server Synapse",
|
||||||
"author": "Awesome Technologies Innovationslabor GmbH",
|
"author": "Awesome Technologies Innovationslabor GmbH",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"@testing-library/user-event": "^13.1.8",
|
"@testing-library/user-event": "^13.1.8",
|
||||||
"eslint": "^7.25.0",
|
"eslint": "^7.25.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-prettier": "^3.1.2",
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"jest-fetch-mock": "^3.0.3",
|
||||||
"prettier": "^2.2.0",
|
"prettier": "^2.2.0",
|
||||||
@ -26,9 +27,9 @@
|
|||||||
"ra-language-chinese": "^2.0.10",
|
"ra-language-chinese": "^2.0.10",
|
||||||
"ra-language-german": "^3.13.4",
|
"ra-language-german": "^3.13.4",
|
||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
"react-admin": "^3.15.0",
|
"react-admin": "^3.19.7",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "^4.0.0"
|
"react-scripts": "^5.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
"start": "REACT_APP_VERSION=$(git describe --tags) react-scripts start",
|
||||||
|
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 { ReportList, ReportShow } from "./components/EventReports";
|
||||||
import LoginPage from "./components/LoginPage";
|
import LoginPage from "./components/LoginPage";
|
||||||
import UserIcon from "@material-ui/icons/Group";
|
import UserIcon from "@material-ui/icons/Group";
|
||||||
|
import ConfirmationNumberIcon from "@material-ui/icons/ConfirmationNumber";
|
||||||
import EqualizerIcon from "@material-ui/icons/Equalizer";
|
import EqualizerIcon from "@material-ui/icons/Equalizer";
|
||||||
import { UserMediaStatsList } from "./components/statistics";
|
import { UserMediaStatsList } from "./components/statistics";
|
||||||
import RoomIcon from "@material-ui/icons/ViewList";
|
import RoomIcon from "@material-ui/icons/ViewList";
|
||||||
import ReportIcon from "@material-ui/icons/Warning";
|
import ReportIcon from "@material-ui/icons/Warning";
|
||||||
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
import FolderSharedIcon from "@material-ui/icons/FolderShared";
|
||||||
import { ImportFeature } from "./components/ImportFeature";
|
import { ImportFeature } from "./components/ImportFeature";
|
||||||
|
import {
|
||||||
|
RegistrationTokenCreate,
|
||||||
|
RegistrationTokenEdit,
|
||||||
|
RegistrationTokenList,
|
||||||
|
} from "./components/RegistrationTokens";
|
||||||
import { RoomDirectoryList } from "./components/RoomDirectory";
|
import { RoomDirectoryList } from "./components/RoomDirectory";
|
||||||
import { Route } from "react-router-dom";
|
import { Route } from "react-router-dom";
|
||||||
import germanMessages from "./i18n/de";
|
import germanMessages from "./i18n/de";
|
||||||
@ -66,6 +72,13 @@ const App = () => (
|
|||||||
list={RoomDirectoryList}
|
list={RoomDirectoryList}
|
||||||
icon={FolderSharedIcon}
|
icon={FolderSharedIcon}
|
||||||
/>
|
/>
|
||||||
|
<Resource
|
||||||
|
name="registration_tokens"
|
||||||
|
list={RegistrationTokenList}
|
||||||
|
create={RegistrationTokenCreate}
|
||||||
|
edit={RegistrationTokenEdit}
|
||||||
|
icon={ConfirmationNumberIcon}
|
||||||
|
/>
|
||||||
<Resource name="connections" />
|
<Resource name="connections" />
|
||||||
<Resource name="devices" />
|
<Resource name="devices" />
|
||||||
<Resource name="room_members" />
|
<Resource name="room_members" />
|
||||||
|
@ -15,6 +15,15 @@ import {
|
|||||||
import PageviewIcon from "@material-ui/icons/Pageview";
|
import PageviewIcon from "@material-ui/icons/Pageview";
|
||||||
import ViewListIcon from "@material-ui/icons/ViewList";
|
import ViewListIcon from "@material-ui/icons/ViewList";
|
||||||
|
|
||||||
|
const date_format = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
};
|
||||||
|
|
||||||
const ReportPagination = props => (
|
const ReportPagination = props => (
|
||||||
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
<Pagination {...props} rowsPerPageOptions={[10, 25, 50, 100, 500, 1000]} />
|
||||||
);
|
);
|
||||||
@ -33,14 +42,7 @@ export const ReportShow = props => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="received_ts"
|
source="received_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={true}
|
sortable={true}
|
||||||
/>
|
/>
|
||||||
<ReferenceField source="user_id" reference="users">
|
<ReferenceField source="user_id" reference="users">
|
||||||
@ -68,18 +70,10 @@ export const ReportShow = props => {
|
|||||||
icon={<PageviewIcon />}
|
icon={<PageviewIcon />}
|
||||||
path="detail"
|
path="detail"
|
||||||
>
|
>
|
||||||
{" "}
|
|
||||||
<DateField
|
<DateField
|
||||||
source="event_json.origin_server_ts"
|
source="event_json.origin_server_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={true}
|
sortable={true}
|
||||||
/>
|
/>
|
||||||
<ReferenceField source="sender" reference="users">
|
<ReferenceField source="sender" reference="users">
|
||||||
@ -116,14 +110,7 @@ export const ReportList = ({ ...props }) => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="received_ts"
|
source="received_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={true}
|
sortable={true}
|
||||||
/>
|
/>
|
||||||
<TextField sortable={false} source="user_id" />
|
<TextField sortable={false} source="user_id" />
|
||||||
|
@ -78,11 +78,48 @@ const LoginPage = ({ theme }) => {
|
|||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const notify = useNotify();
|
const notify = useNotify();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [supportPassAuth, setSupportPassAuth] = useState(true);
|
||||||
var locale = useLocale();
|
var locale = useLocale();
|
||||||
const setLocale = useSetLocale();
|
const setLocale = useSetLocale();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
const base_url = localStorage.getItem("base_url");
|
const base_url = localStorage.getItem("base_url");
|
||||||
const cfg_base_url = process.env.REACT_APP_SERVER;
|
const cfg_base_url = process.env.REACT_APP_SERVER;
|
||||||
|
const [ssoBaseUrl, setSSOBaseUrl] = useState("");
|
||||||
|
const loginToken = /\?loginToken=([a-zA-Z0-9_-]+)/.exec(window.location.href);
|
||||||
|
|
||||||
|
if (loginToken) {
|
||||||
|
const ssoToken = loginToken[1];
|
||||||
|
console.log("SSO token is", ssoToken);
|
||||||
|
// Prevent further requests
|
||||||
|
window.history.replaceState(
|
||||||
|
{},
|
||||||
|
"",
|
||||||
|
window.location.href.replace(loginToken[0], "#").split("#")[0]
|
||||||
|
);
|
||||||
|
const baseUrl = localStorage.getItem("sso_base_url");
|
||||||
|
localStorage.removeItem("sso_base_url");
|
||||||
|
if (baseUrl) {
|
||||||
|
const auth = {
|
||||||
|
base_url: baseUrl,
|
||||||
|
username: null,
|
||||||
|
password: null,
|
||||||
|
loginToken: ssoToken,
|
||||||
|
};
|
||||||
|
console.log("Base URL is:", baseUrl);
|
||||||
|
console.log("SSO Token is:", ssoToken);
|
||||||
|
console.log("Let's try token login...");
|
||||||
|
login(auth).catch(error => {
|
||||||
|
alert(
|
||||||
|
typeof error === "string"
|
||||||
|
? error
|
||||||
|
: typeof error === "undefined" || !error.message
|
||||||
|
? "ra.auth.sign_in_error"
|
||||||
|
: error.message
|
||||||
|
);
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const renderInput = ({
|
const renderInput = ({
|
||||||
meta: { touched, error } = {},
|
meta: { touched, error } = {},
|
||||||
@ -137,6 +174,14 @@ const LoginPage = ({ theme }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSSO = () => {
|
||||||
|
localStorage.setItem("sso_base_url", ssoBaseUrl);
|
||||||
|
const ssoFullUrl = `${ssoBaseUrl}/_matrix/client/r0/login/sso/redirect?redirectUrl=${encodeURIComponent(
|
||||||
|
window.location.href
|
||||||
|
)}`;
|
||||||
|
window.location.href = ssoFullUrl;
|
||||||
|
};
|
||||||
|
|
||||||
const extractHomeServer = username => {
|
const extractHomeServer = username => {
|
||||||
const usernameRegex = /@[a-zA-Z0-9._=\-/]+:([a-zA-Z0-9\-.]+\.[a-zA-Z]+)/;
|
const usernameRegex = /@[a-zA-Z0-9._=\-/]+:([a-zA-Z0-9\-.]+\.[a-zA-Z]+)/;
|
||||||
if (!username) return null;
|
if (!username) return null;
|
||||||
@ -188,6 +233,31 @@ const LoginPage = ({ theme }) => {
|
|||||||
.catch(_ => {
|
.catch(_ => {
|
||||||
setServerVersion("");
|
setServerVersion("");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set SSO Url
|
||||||
|
const authMethodUrl = `${formData.base_url}/_matrix/client/r0/login`;
|
||||||
|
let supportPass = false,
|
||||||
|
supportSSO = false;
|
||||||
|
fetchUtils
|
||||||
|
.fetchJson(authMethodUrl, { method: "GET" })
|
||||||
|
.then(({ json }) => {
|
||||||
|
json.flows.forEach(f => {
|
||||||
|
if (f.type === "m.login.password") {
|
||||||
|
supportPass = true;
|
||||||
|
} else if (f.type === "m.login.sso") {
|
||||||
|
supportSSO = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setSupportPassAuth(supportPass);
|
||||||
|
if (supportSSO) {
|
||||||
|
setSSOBaseUrl(formData.base_url);
|
||||||
|
} else {
|
||||||
|
setSSOBaseUrl("");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(_ => {
|
||||||
|
setSSOBaseUrl("");
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[formData.base_url]
|
[formData.base_url]
|
||||||
);
|
);
|
||||||
@ -200,7 +270,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
name="username"
|
name="username"
|
||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("ra.auth.username")}
|
label={translate("ra.auth.username")}
|
||||||
disabled={loading}
|
disabled={loading || !supportPassAuth}
|
||||||
onBlur={handleUsernameChange}
|
onBlur={handleUsernameChange}
|
||||||
resettable
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -212,7 +282,7 @@ const LoginPage = ({ theme }) => {
|
|||||||
component={renderInput}
|
component={renderInput}
|
||||||
label={translate("ra.auth.password")}
|
label={translate("ra.auth.password")}
|
||||||
type="password"
|
type="password"
|
||||||
disabled={loading}
|
disabled={loading || !supportPassAuth}
|
||||||
resettable
|
resettable
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
@ -273,13 +343,24 @@ const LoginPage = ({ theme }) => {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
type="submit"
|
type="submit"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={loading}
|
disabled={loading || !supportPassAuth}
|
||||||
className={classes.button}
|
className={classes.button}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
{loading && <CircularProgress size={25} thickness={2} />}
|
{loading && <CircularProgress size={25} thickness={2} />}
|
||||||
{translate("ra.auth.sign_in")}
|
{translate("ra.auth.sign_in")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="secondary"
|
||||||
|
onClick={handleSSO}
|
||||||
|
disabled={loading || ssoBaseUrl === ""}
|
||||||
|
className={classes.button}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
{loading && <CircularProgress size={25} thickness={2} />}
|
||||||
|
{translate("synapseadmin.auth.sso_sign_in")}
|
||||||
|
</Button>
|
||||||
</CardActions>
|
</CardActions>
|
||||||
</Card>
|
</Card>
|
||||||
<Notification />
|
<Notification />
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
@ -8,7 +8,7 @@ import {
|
|||||||
} from "react-admin";
|
} from "react-admin";
|
||||||
import ActionDelete from "@material-ui/icons/Delete";
|
import ActionDelete from "@material-ui/icons/Delete";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { alpha } from "@material-ui/core/styles/colorManipulator";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
@ -16,7 +16,7 @@ const useStyles = makeStyles(
|
|||||||
deleteButton: {
|
deleteButton: {
|
||||||
color: theme.palette.error.main,
|
color: theme.palette.error.main,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: fade(theme.palette.error.main, 0.12),
|
backgroundColor: alpha(theme.palette.error.main, 0.12),
|
||||||
// Reset on mouse devices
|
// Reset on mouse devices
|
||||||
"@media (hover: none)": {
|
"@media (hover: none)": {
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { Fragment, useState } from "react";
|
import React, { Fragment, useState } from "react";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
import { alpha } from "@material-ui/core/styles/colorManipulator";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { Tooltip } from "@material-ui/core";
|
import { Tooltip } from "@material-ui/core";
|
||||||
import {
|
import {
|
||||||
@ -33,7 +33,7 @@ const useStyles = makeStyles(
|
|||||||
deleteButton: {
|
deleteButton: {
|
||||||
color: theme.palette.error.main,
|
color: theme.palette.error.main,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
backgroundColor: fade(theme.palette.error.main, 0.12),
|
backgroundColor: alpha(theme.palette.error.main, 0.12),
|
||||||
// Reset on mouse devices
|
// Reset on mouse devices
|
||||||
"@media (hover: none)": {
|
"@media (hover: none)": {
|
||||||
backgroundColor: "transparent",
|
backgroundColor: "transparent",
|
||||||
|
@ -41,6 +41,15 @@ import {
|
|||||||
RoomDirectorySaveButton,
|
RoomDirectorySaveButton,
|
||||||
} from "./RoomDirectory";
|
} from "./RoomDirectory";
|
||||||
|
|
||||||
|
const date_format = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
};
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
helper_forward_extremities: {
|
helper_forward_extremities: {
|
||||||
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
fontFamily: "Roboto, Helvetica, Arial, sans-serif",
|
||||||
@ -149,7 +158,11 @@ export const RoomShow = props => {
|
|||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
||||||
<Tab label="synapseadmin.rooms.tabs.members" icon={<UserIcon />}>
|
<Tab
|
||||||
|
label="synapseadmin.rooms.tabs.members"
|
||||||
|
icon={<UserIcon />}
|
||||||
|
path="members"
|
||||||
|
>
|
||||||
<ReferenceManyField
|
<ReferenceManyField
|
||||||
reference="room_members"
|
reference="room_members"
|
||||||
target="room_id"
|
target="room_id"
|
||||||
@ -247,14 +260,7 @@ export const RoomShow = props => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="origin_server_ts"
|
source="origin_server_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={false}
|
sortable={false}
|
||||||
/>
|
/>
|
||||||
<TextField source="content" sortable={false} />
|
<TextField source="content" sortable={false} />
|
||||||
@ -287,14 +293,7 @@ export const RoomShow = props => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="received_ts"
|
source="received_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={false}
|
sortable={false}
|
||||||
/>
|
/>
|
||||||
<NumberField source="depth" sortable={false} />
|
<NumberField source="depth" sortable={false} />
|
||||||
|
@ -71,6 +71,25 @@ const useStyles = makeStyles({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const choices_medium = [
|
||||||
|
{ id: "email", name: "resources.users.email" },
|
||||||
|
{ id: "msisdn", name: "resources.users.msisdn" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const choices_type = [
|
||||||
|
{ id: "bot", name: "bot" },
|
||||||
|
{ id: "support", name: "support" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const date_format = {
|
||||||
|
year: "numeric",
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
};
|
||||||
|
|
||||||
const UserListActions = ({
|
const UserListActions = ({
|
||||||
currentSort,
|
currentSort,
|
||||||
className,
|
className,
|
||||||
@ -176,6 +195,12 @@ export const UserList = props => {
|
|||||||
<BooleanField source="is_guest" />
|
<BooleanField source="is_guest" />
|
||||||
<BooleanField source="admin" />
|
<BooleanField source="admin" />
|
||||||
<BooleanField source="deactivated" />
|
<BooleanField source="deactivated" />
|
||||||
|
<DateField
|
||||||
|
source="creation_ts"
|
||||||
|
label="resources.users.fields.creation_ts_ms"
|
||||||
|
showTime
|
||||||
|
options={date_format}
|
||||||
|
/>
|
||||||
</Datagrid>
|
</Datagrid>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
@ -261,22 +286,26 @@ export const UserCreate = props => (
|
|||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
validate={maxLength(512)}
|
validate={maxLength(512)}
|
||||||
/>
|
/>
|
||||||
|
<SelectInput
|
||||||
|
source="user_type"
|
||||||
|
choices={choices_type}
|
||||||
|
translateChoice={false}
|
||||||
|
allowEmpty={true}
|
||||||
|
resettable
|
||||||
|
/>
|
||||||
<BooleanInput source="admin" />
|
<BooleanInput source="admin" />
|
||||||
<ArrayInput source="threepids">
|
<ArrayInput source="threepids">
|
||||||
<SimpleFormIterator>
|
<SimpleFormIterator disableReordering>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
source="medium"
|
source="medium"
|
||||||
choices={[
|
choices={choices_medium}
|
||||||
{ id: "email", name: "resources.users.email" },
|
|
||||||
{ id: "msisdn", name: "resources.users.msisdn" },
|
|
||||||
]}
|
|
||||||
validate={required()}
|
validate={required()}
|
||||||
/>
|
/>
|
||||||
<TextInput source="address" validate={validateAddress} />
|
<TextInput source="address" validate={validateAddress} />
|
||||||
</SimpleFormIterator>
|
</SimpleFormIterator>
|
||||||
</ArrayInput>
|
</ArrayInput>
|
||||||
<ArrayInput source="external_ids" label="synapseadmin.users.tabs.sso">
|
<ArrayInput source="external_ids" label="synapseadmin.users.tabs.sso">
|
||||||
<SimpleFormIterator>
|
<SimpleFormIterator disableReordering>
|
||||||
<TextInput source="auth_provider" validate={required()} />
|
<TextInput source="auth_provider" validate={required()} />
|
||||||
<TextInput
|
<TextInput
|
||||||
source="external_id"
|
source="external_id"
|
||||||
@ -300,6 +329,7 @@ const UserTitle = ({ record }) => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserEdit = props => {
|
export const UserEdit = props => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const translate = useTranslate();
|
const translate = useTranslate();
|
||||||
@ -322,23 +352,19 @@ export const UserEdit = props => {
|
|||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
helperText="resources.users.helper.password"
|
helperText="resources.users.helper.password"
|
||||||
/>
|
/>
|
||||||
|
<SelectInput
|
||||||
|
source="user_type"
|
||||||
|
choices={choices_type}
|
||||||
|
translateChoice={false}
|
||||||
|
allowEmpty={true}
|
||||||
|
resettable
|
||||||
|
/>
|
||||||
<BooleanInput source="admin" />
|
<BooleanInput source="admin" />
|
||||||
<BooleanInput
|
<BooleanInput
|
||||||
source="deactivated"
|
source="deactivated"
|
||||||
helperText="resources.users.helper.deactivate"
|
helperText="resources.users.helper.deactivate"
|
||||||
/>
|
/>
|
||||||
<DateField
|
<DateField source="creation_ts_ms" showTime options={date_format} />
|
||||||
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" />
|
<TextField source="consent_version" />
|
||||||
</FormTab>
|
</FormTab>
|
||||||
|
|
||||||
@ -348,14 +374,8 @@ export const UserEdit = props => {
|
|||||||
path="threepid"
|
path="threepid"
|
||||||
>
|
>
|
||||||
<ArrayInput source="threepids">
|
<ArrayInput source="threepids">
|
||||||
<SimpleFormIterator>
|
<SimpleFormIterator disableReordering>
|
||||||
<SelectInput
|
<SelectInput source="medium" choices={choices_medium} />
|
||||||
source="medium"
|
|
||||||
choices={[
|
|
||||||
{ id: "email", name: "resources.users.email" },
|
|
||||||
{ id: "msisdn", name: "resources.users.msisdn" },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<TextInput source="address" />
|
<TextInput source="address" />
|
||||||
</SimpleFormIterator>
|
</SimpleFormIterator>
|
||||||
</ArrayInput>
|
</ArrayInput>
|
||||||
@ -367,7 +387,7 @@ export const UserEdit = props => {
|
|||||||
path="sso"
|
path="sso"
|
||||||
>
|
>
|
||||||
<ArrayInput source="external_ids" label={false}>
|
<ArrayInput source="external_ids" label={false}>
|
||||||
<SimpleFormIterator>
|
<SimpleFormIterator disableReordering>
|
||||||
<TextInput source="auth_provider" validate={required()} />
|
<TextInput source="auth_provider" validate={required()} />
|
||||||
<TextInput
|
<TextInput
|
||||||
source="external_id"
|
source="external_id"
|
||||||
@ -395,14 +415,7 @@ export const UserEdit = props => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="last_seen_ts"
|
source="last_seen_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={false}
|
sortable={false}
|
||||||
/>
|
/>
|
||||||
<DeviceRemoveButton />
|
<DeviceRemoveButton />
|
||||||
@ -430,14 +443,7 @@ export const UserEdit = props => {
|
|||||||
<DateField
|
<DateField
|
||||||
source="last_seen"
|
source="last_seen"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
sortable={false}
|
sortable={false}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@ -464,29 +470,11 @@ export const UserEdit = props => {
|
|||||||
sort={{ field: "created_ts", order: "DESC" }}
|
sort={{ field: "created_ts", order: "DESC" }}
|
||||||
>
|
>
|
||||||
<Datagrid style={{ width: "100%" }}>
|
<Datagrid style={{ width: "100%" }}>
|
||||||
<DateField
|
<DateField source="created_ts" showTime options={date_format} />
|
||||||
source="created_ts"
|
|
||||||
showTime
|
|
||||||
options={{
|
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<DateField
|
<DateField
|
||||||
source="last_access_ts"
|
source="last_access_ts"
|
||||||
showTime
|
showTime
|
||||||
options={{
|
options={date_format}
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
second: "2-digit",
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextField source="media_id" />
|
<TextField source="media_id" />
|
||||||
<NumberField source="media_length" />
|
<NumberField source="media_length" />
|
||||||
|
@ -10,6 +10,7 @@ const de = {
|
|||||||
username_error: "Bitte vollständigen Nutzernamen angeben: '@user:domain'",
|
username_error: "Bitte vollständigen Nutzernamen angeben: '@user:domain'",
|
||||||
protocol_error: "Die URL muss mit 'http://' oder 'https://' beginnen",
|
protocol_error: "Die URL muss mit 'http://' oder 'https://' beginnen",
|
||||||
url_error: "Keine gültige Matrix Server URL",
|
url_error: "Keine gültige Matrix Server URL",
|
||||||
|
sso_sign_in: "Anmeldung mit SSO",
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
invalid_user_id: "Lokaler Anteil der Matrix Benutzer-ID ohne Homeserver.",
|
invalid_user_id: "Lokaler Anteil der Matrix Benutzer-ID ohne Homeserver.",
|
||||||
@ -96,7 +97,6 @@ const de = {
|
|||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
users: {
|
users: {
|
||||||
backtolist: "Zurück zur Liste",
|
|
||||||
name: "Benutzer",
|
name: "Benutzer",
|
||||||
email: "E-Mail",
|
email: "E-Mail",
|
||||||
msisdn: "Telefon",
|
msisdn: "Telefon",
|
||||||
@ -121,6 +121,7 @@ const de = {
|
|||||||
creation_ts_ms: "Zeitpunkt der Erstellung",
|
creation_ts_ms: "Zeitpunkt der Erstellung",
|
||||||
consent_version: "Zugestimmte Geschäftsbedingungen",
|
consent_version: "Zugestimmte Geschäftsbedingungen",
|
||||||
auth_provider: "Provider",
|
auth_provider: "Provider",
|
||||||
|
user_type: "Benutzertyp",
|
||||||
},
|
},
|
||||||
helper: {
|
helper: {
|
||||||
password: "Durch die Änderung des Passworts wird der Benutzer von allen Sitzungen abgemeldet.",
|
password: "Durch die Änderung des Passworts wird der Benutzer von allen Sitzungen abgemeldet.",
|
||||||
@ -353,6 +354,19 @@ const de = {
|
|||||||
send_failure: "Beim Entfernen ist ein Fehler aufgetreten.",
|
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: {
|
ra: {
|
||||||
...germanMessages.ra,
|
...germanMessages.ra,
|
||||||
@ -373,7 +387,7 @@ const de = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
...germanMessages.ra.notifiaction,
|
...germanMessages.ra.notification,
|
||||||
logged_out: "Abgemeldet",
|
logged_out: "Abgemeldet",
|
||||||
},
|
},
|
||||||
page: {
|
page: {
|
||||||
|
@ -10,6 +10,7 @@ const en = {
|
|||||||
username_error: "Please enter fully qualified user ID: '@user:domain'",
|
username_error: "Please enter fully qualified user ID: '@user:domain'",
|
||||||
protocol_error: "URL has to start with 'http://' or 'https://'",
|
protocol_error: "URL has to start with 'http://' or 'https://'",
|
||||||
url_error: "Not a valid Matrix server URL",
|
url_error: "Not a valid Matrix server URL",
|
||||||
|
sso_sign_in: "Sign in with SSO",
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
invalid_user_id: "Localpart of a Matrix user-id without homeserver.",
|
invalid_user_id: "Localpart of a Matrix user-id without homeserver.",
|
||||||
@ -95,7 +96,6 @@ const en = {
|
|||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
users: {
|
users: {
|
||||||
backtolist: "Back to list",
|
|
||||||
name: "User |||| Users",
|
name: "User |||| Users",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
msisdn: "Phone",
|
msisdn: "Phone",
|
||||||
@ -120,6 +120,7 @@ const en = {
|
|||||||
creation_ts_ms: "Creation timestamp",
|
creation_ts_ms: "Creation timestamp",
|
||||||
consent_version: "Consent version",
|
consent_version: "Consent version",
|
||||||
auth_provider: "Provider",
|
auth_provider: "Provider",
|
||||||
|
user_type: "User type",
|
||||||
},
|
},
|
||||||
helper: {
|
helper: {
|
||||||
password: "Changing password will log user out of all sessions.",
|
password: "Changing password will log user out of all sessions.",
|
||||||
@ -175,10 +176,12 @@ const en = {
|
|||||||
},
|
},
|
||||||
unencrypted: "Unencrypted",
|
unencrypted: "Unencrypted",
|
||||||
},
|
},
|
||||||
erase: {
|
action: {
|
||||||
title: "Delete room",
|
erase: {
|
||||||
content:
|
title: "Delete room",
|
||||||
"Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!",
|
content:
|
||||||
|
"Are you sure you want to delete the room? This cannot be undone. All messages and shared media in the room will be deleted from the server!",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reports: {
|
reports: {
|
||||||
@ -350,5 +353,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;
|
export default en;
|
||||||
|
@ -10,10 +10,12 @@ const zh = {
|
|||||||
username_error: "请输入完整有效的用户 ID: '@user:domain'",
|
username_error: "请输入完整有效的用户 ID: '@user:domain'",
|
||||||
protocol_error: "URL 需要以'http://'或'https://'作为起始",
|
protocol_error: "URL 需要以'http://'或'https://'作为起始",
|
||||||
url_error: "不是一个有效的 Matrix 服务器地址",
|
url_error: "不是一个有效的 Matrix 服务器地址",
|
||||||
|
sso_sign_in: "使用 SSO 登录",
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
invalid_user_id:
|
invalid_user_id:
|
||||||
"必须要是一个有效的 Matrix 用户 ID ,例如 @user_id:homeserver",
|
"必须要是一个有效的 Matrix 用户 ID ,例如 @user_id:homeserver",
|
||||||
|
tabs: { sso: "SSO" },
|
||||||
},
|
},
|
||||||
rooms: {
|
rooms: {
|
||||||
tabs: {
|
tabs: {
|
||||||
@ -98,7 +100,6 @@ const zh = {
|
|||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
users: {
|
users: {
|
||||||
backtolist: "回到列表",
|
|
||||||
name: "用户",
|
name: "用户",
|
||||||
email: "邮箱",
|
email: "邮箱",
|
||||||
msisdn: "电话",
|
msisdn: "电话",
|
||||||
|
@ -2,20 +2,31 @@ import { fetchUtils } from "react-admin";
|
|||||||
|
|
||||||
const authProvider = {
|
const authProvider = {
|
||||||
// called when the user attempts to log in
|
// called when the user attempts to log in
|
||||||
login: ({ base_url, username, password }) => {
|
login: ({ base_url, username, password, loginToken }) => {
|
||||||
// force homeserver for protection in case the form is manipulated
|
// force homeserver for protection in case the form is manipulated
|
||||||
base_url = process.env.REACT_APP_SERVER || base_url;
|
base_url = process.env.REACT_APP_SERVER || base_url;
|
||||||
|
|
||||||
console.log("login ");
|
console.log("login ");
|
||||||
const options = {
|
const options = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(
|
||||||
type: "m.login.password",
|
Object.assign(
|
||||||
user: username,
|
{
|
||||||
password: password,
|
device_id: localStorage.getItem("device_id"),
|
||||||
device_id: localStorage.getItem("device_id"),
|
initial_device_display_name: "Synapse Admin",
|
||||||
initial_device_display_name: "Synapse Admin",
|
},
|
||||||
}),
|
loginToken
|
||||||
|
? {
|
||||||
|
type: "m.login.token",
|
||||||
|
token: loginToken,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: "m.login.password",
|
||||||
|
user: username,
|
||||||
|
password: password,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
// use the base_url from login instead of the well_known entry from the
|
// use the base_url from login instead of the well_known entry from the
|
||||||
|
@ -275,11 +275,31 @@ const resourceMap = {
|
|||||||
method: "PUT",
|
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) {
|
function filterNullValues(key, value) {
|
||||||
// Filtering out null properties
|
// Filtering out null properties
|
||||||
if (value === null) {
|
// to reset user_type from user, it must be null
|
||||||
|
if (value === null && key !== "user_type") {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
@ -296,7 +316,8 @@ function getSearchOrder(order) {
|
|||||||
const dataProvider = {
|
const dataProvider = {
|
||||||
getList: (resource, params) => {
|
getList: (resource, params) => {
|
||||||
console.log("getList " + resource);
|
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 { page, perPage } = params.pagination;
|
||||||
const { field, order } = params.sort;
|
const { field, order } = params.sort;
|
||||||
const from = (page - 1) * perPage;
|
const from = (page - 1) * perPage;
|
||||||
@ -308,6 +329,7 @@ const dataProvider = {
|
|||||||
name: name,
|
name: name,
|
||||||
guests: guests,
|
guests: guests,
|
||||||
deactivated: deactivated,
|
deactivated: deactivated,
|
||||||
|
valid: valid,
|
||||||
order_by: field,
|
order_by: field,
|
||||||
dir: getSearchOrder(order),
|
dir: getSearchOrder(order),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user